Skip to content

Commit

Permalink
[EDR Workflows][Osquery] Adapt to policy_ids array instead of policy_…
Browse files Browse the repository at this point in the history
…id (#193150)

(cherry picked from commit 2994392)
  • Loading branch information
tomsonpl committed Sep 18, 2024
1 parent 0ff66b4 commit 0b44211
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 49 deletions.
4 changes: 2 additions & 2 deletions x-pack/plugins/osquery/public/agents/use_osquery_policies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,43 @@ 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(
(event: any) => {
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, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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(() => {
/*
Expand Down Expand Up @@ -363,32 +388,40 @@ 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>
</EuiFlexGroup>
<EuiSpacer />
</>
) : null}

{!permissionDenied && (
<>
<NavigationButtons isDisabled={!editMode} agentPolicyId={policy?.policy_id} />
<NavigationButtons isDisabled={!editMode} agentPolicyIds={policyIdsWithAgents} />
<EuiSpacer size="xxl" />
<EuiAccordion
css={euiAccordionCss}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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(() => {
Expand Down Expand Up @@ -68,7 +73,7 @@ const NewLiveQueryPageComponent = () => {

return (
<WithHeaderLayout leftColumn={LeftColumn}>
<LiveQuery agentPolicyIds={agentPolicyIds} {...initialFormData} />
<LiveQuery {...initialFormData} agentPolicyIds={agentPolicyIds} />
</WithHeaderLayout>
);
};
Expand Down

0 comments on commit 0b44211

Please sign in to comment.