Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fleet UI: VPP auto install software on failed policies, filter software compatible to policy's target platform, etc #25202

Merged
merged 15 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changes/23528-install-software-policy-filter
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Improved software installation for failed policies: Added platform-specific filtering in the software dropdown, ensuring only compatible software are displayed based on each policy's targeted platforms
- Add VPP app to automatic installation dropdown for failed policies and auto install information on VPP app details page
14 changes: 9 additions & 5 deletions frontend/context/policy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { find } from "lodash";

import { osqueryTables } from "utilities/osquery_tables";
import { IOsQueryTable, DEFAULT_OSQUERY_TABLE } from "interfaces/osquery_table";
import { SelectedPlatformString } from "interfaces/platform";
import { CommaSeparatedPlatformString } from "interfaces/platform";

enum ACTIONS {
SET_LAST_EDITED_QUERY_INFO = "SET_LAST_EDITED_QUERY_INFO",
Expand All @@ -25,7 +25,7 @@ interface ISetLastEditedQueryInfo {
lastEditedQueryBody?: string;
lastEditedQueryResolution?: string;
lastEditedQueryCritical?: boolean;
lastEditedQueryPlatform?: SelectedPlatformString | null;
lastEditedQueryPlatform?: CommaSeparatedPlatformString | null;
defaultPolicy?: boolean;
}

Expand Down Expand Up @@ -55,15 +55,17 @@ type InitialStateType = {
lastEditedQueryBody: string;
lastEditedQueryResolution: string;
lastEditedQueryCritical: boolean;
lastEditedQueryPlatform: SelectedPlatformString | null;
lastEditedQueryPlatform: CommaSeparatedPlatformString | null;
defaultPolicy: boolean;
setLastEditedQueryId: (value: number | null) => void;
setLastEditedQueryName: (value: string) => void;
setLastEditedQueryDescription: (value: string) => void;
setLastEditedQueryBody: (value: string) => void;
setLastEditedQueryResolution: (value: string) => void;
setLastEditedQueryCritical: (value: boolean) => void;
setLastEditedQueryPlatform: (value: SelectedPlatformString | null) => void;
setLastEditedQueryPlatform: (
value: CommaSeparatedPlatformString | null
) => void;
setDefaultPolicy: (value: boolean) => void;
policyTeamId: number;
setPolicyTeamId: (id: number) => void;
Expand Down Expand Up @@ -216,7 +218,9 @@ const PolicyProvider = ({ children }: Props): JSX.Element => {
[]
);
const setLastEditedQueryPlatform = useCallback(
(lastEditedQueryPlatform: SelectedPlatformString | null | undefined) => {
(
lastEditedQueryPlatform: CommaSeparatedPlatformString | null | undefined
) => {
dispatch({
type: ACTIONS.SET_LAST_EDITED_QUERY_INFO,
lastEditedQueryPlatform,
Expand Down
6 changes: 3 additions & 3 deletions frontend/context/query.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { find } from "lodash";
import { osqueryTables } from "utilities/osquery_tables";
import { DEFAULT_QUERY } from "utilities/constants";
import { DEFAULT_OSQUERY_TABLE, IOsQueryTable } from "interfaces/osquery_table";
import { SelectedPlatformString } from "interfaces/platform";
import { CommaSeparatedPlatformString } from "interfaces/platform";
import { QueryLoggingOption } from "interfaces/schedulable_query";
import {
DEFAULT_TARGETS,
Expand All @@ -26,7 +26,7 @@ type InitialStateType = {
lastEditedQueryObserverCanRun: boolean;
lastEditedQueryFrequency: number;
lastEditedQueryAutomationsEnabled: boolean;
lastEditedQueryPlatforms: SelectedPlatformString;
lastEditedQueryPlatforms: CommaSeparatedPlatformString;
lastEditedQueryMinOsqueryVersion: string;
lastEditedQueryLoggingType: QueryLoggingOption;
lastEditedQueryDiscardData: boolean;
Expand All @@ -40,7 +40,7 @@ type InitialStateType = {
setLastEditedQueryObserverCanRun: (value: boolean) => void;
setLastEditedQueryFrequency: (value: number) => void;
setLastEditedQueryAutomationsEnabled: (value: boolean) => void;
setLastEditedQueryPlatforms: (value: SelectedPlatformString) => void;
setLastEditedQueryPlatforms: (value: CommaSeparatedPlatformString) => void;
setLastEditedQueryMinOsqueryVersion: (value: string) => void;
setLastEditedQueryLoggingType: (value: string) => void;
setLastEditedQueryDiscardData: (value: boolean) => void;
Expand Down
4 changes: 2 additions & 2 deletions frontend/hooks/usePlatformSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useState } from "react";
import { forEach } from "lodash";

import {
SelectedPlatformString,
CommaSeparatedPlatformString,
QUERYABLE_PLATFORMS,
QueryablePlatform,
} from "interfaces/platform";
Expand All @@ -21,7 +21,7 @@ export interface IPlatformSelector {
}

const usePlatformSelector = (
platformContext: SelectedPlatformString | null | undefined,
platformContext: CommaSeparatedPlatformString | null | undefined,
baseClass = "",
disabled = false,
installSoftware: IPolicySoftwareToInstall | undefined,
Expand Down
2 changes: 1 addition & 1 deletion frontend/interfaces/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const VULN_SUPPORTED_PLATFORMS: Platform[] = ["darwin", "windows"];

export type SelectedPlatform = QueryablePlatform | "all";

export type SelectedPlatformString =
export type CommaSeparatedPlatformString =
| ""
| QueryablePlatform
| `${QueryablePlatform},${QueryablePlatform}`
Expand Down
8 changes: 4 additions & 4 deletions frontend/interfaces/policy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import PropTypes from "prop-types";
import { SelectedPlatformString } from "interfaces/platform";
import { CommaSeparatedPlatformString } from "interfaces/platform";
import { IScript } from "./script";

// Legacy PropTypes used on host interface
Expand Down Expand Up @@ -36,7 +36,7 @@ export interface IPolicy {
author_name: string;
author_email: string;
resolution: string;
platform: SelectedPlatformString;
platform: CommaSeparatedPlatformString;
team_id: number | null;
created_at: string;
updated_at: string;
Expand Down Expand Up @@ -99,7 +99,7 @@ export interface IPolicyFormData {
description?: string | number | boolean | undefined;
resolution?: string | number | boolean | undefined;
critical?: boolean;
platform?: SelectedPlatformString;
platform?: CommaSeparatedPlatformString;
name?: string | number | boolean | undefined;
query?: string | number | boolean | undefined;
team_id?: number | null;
Expand All @@ -118,6 +118,6 @@ export interface IPolicyNew {
query: string;
resolution: string;
critical: boolean;
platform: SelectedPlatformString;
platform: CommaSeparatedPlatformString;
mdm_required?: boolean;
}
10 changes: 5 additions & 5 deletions frontend/interfaces/schedulable_query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import PropTypes from "prop-types";
import { IFormField } from "./form_field";
import { IPack } from "./pack";
import {
SelectedPlatformString,
CommaSeparatedPlatformString,
QueryablePlatform,
SelectedPlatform,
} from "./platform";
Expand All @@ -19,7 +19,7 @@ export interface ISchedulableQuery {
query: string;
team_id: number | null;
interval: number;
platform: SelectedPlatformString; // Might more accurately be called `platforms_to_query` or `targeted_platforms` – comma-sepparated string of platforms to query, default all platforms if ommitted
platform: CommaSeparatedPlatformString; // Might more accurately be called `platforms_to_query` or `targeted_platforms` – comma-separated string of platforms to query, default all platforms if omitted
min_osquery_version: string;
automations_enabled: boolean;
logging: QueryLoggingOption;
Expand Down Expand Up @@ -90,7 +90,7 @@ export interface ICreateQueryRequestBody {
discard_data?: boolean;
team_id?: number; // global query if ommitted
interval?: number; // default 0 means never run
platform?: SelectedPlatformString; // Might more accurately be called `platforms_to_query` – comma-sepparated string of platforms to query, default all platforms if ommitted
platform?: CommaSeparatedPlatformString; // Might more accurately be called `platforms_to_query` – comma-separated string of platforms to query, default all platforms if omitted
min_osquery_version?: string; // default all versions if ommitted
automations_enabled?: boolean; // whether to send data to the configured log destination according to the query's `interval`. Default false if ommitted.
logging?: QueryLoggingOption;
Expand All @@ -109,7 +109,7 @@ export interface IModifyQueryRequestBody
observer_can_run?: boolean;
discard_data?: boolean;
frequency?: number;
platform?: SelectedPlatformString;
platform?: CommaSeparatedPlatformString;
min_osquery_version?: string;
automations_enabled?: boolean;
}
Expand Down Expand Up @@ -144,7 +144,7 @@ export interface IEditQueryFormFields {
discard_data: IFormField<boolean>;
frequency: IFormField<number>;
automations_enabled: IFormField<boolean>;
platforms: IFormField<SelectedPlatformString>;
platforms: IFormField<CommaSeparatedPlatformString>;
min_osquery_version: IFormField<string>;
logging: IFormField<QueryLoggingOption>;
}
Expand Down
43 changes: 40 additions & 3 deletions frontend/interfaces/software.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export interface ISoftware {
name: string; // e.g., "Figma.app"
version: string; // e.g., "2.1.11"
bundle_identifier?: string | null; // e.g., "com.figma.Desktop"
source: string; // "apps" | "ipados_apps" | "ios_apps" | "programs" | ?
source: string; // "apps" | "ipados_apps" | "ios_apps" | "programs" | "rpm_packages" | "deb_packages" | ?
generated_cpe: string;
vulnerabilities: ISoftwareVulnerability[] | null;
hosts_count?: number;
Expand All @@ -56,7 +56,7 @@ export interface ISoftwareTitleVersion {
hosts_count?: number;
}

export interface ISoftwarePackagePolicy {
export interface ISoftwareInstallPolicy {
id: number;
name: string;
}
Expand All @@ -82,7 +82,7 @@ export interface ISoftwarePackage {
pending_uninstall: number;
failed_uninstall: number;
};
automatic_install_policies?: ISoftwarePackagePolicy[] | null;
automatic_install_policies?: ISoftwareInstallPolicy[] | null;
install_during_setup?: boolean;
labels_include_any: ILabelSoftwareTitle[] | null;
labels_exclude_any: ILabelSoftwareTitle[] | null;
Expand All @@ -105,6 +105,17 @@ export interface IAppStoreApp {
failed: number;
};
install_during_setup?: boolean;
automatic_install_policies?: ISoftwareInstallPolicy[] | null;
last_install?: {
install_uuid: string;
command_uuid: string;
installed_at: string;
} | null;
last_uninstall?: {
script_execution_id: string;
uninstalled_at: string;
} | null;
version?: string;
}

export interface ISoftwareTitle {
Expand Down Expand Up @@ -185,6 +196,32 @@ export const SOURCE_TYPE_CONVERSION = {

export type SoftwareSource = keyof typeof SOURCE_TYPE_CONVERSION;

/** Map installable software source to platform */
export const INSTALLABLE_SOURCE_PLATFORM_CONVERSION = {
apt_sources: "linux",
deb_packages: "linux",
portage_packages: "linux",
rpm_packages: "linux",
yum_sources: "linux",
npm_packages: null,
atom_packages: null,
python_packages: null,
apps: "darwin",
ios_apps: "ios",
ipados_apps: "ipados",
chrome_extensions: null,
firefox_addons: null,
safari_extensions: null,
homebrew_packages: "darwin",
programs: "windows",
ie_extensions: null,
chocolatey_packages: "windows",
pkg_packages: "darwin",
vscode_extensions: null,
} as const;

export type InstallableSoftwareSource = keyof typeof INSTALLABLE_SOURCE_PLATFORM_CONVERSION;

const BROWSER_TYPE_CONVERSION = {
chrome: "Chrome",
chromium: "Chromium",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ const FleetMaintainedAppDetailsPage = ({
isError: isErrorFleetApp,
} = useQuery(
["fleet-maintained-app", appId],
() => softwareAPI.getFleetMainainedApp(appId),
() => softwareAPI.getFleetMaintainedApp(appId),
{
...DEFAULT_USE_QUERY_OPTIONS,
enabled: isPremiumTier,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";

import { ISoftwarePackagePolicy } from "interfaces/software";
import { ISoftwareInstallPolicy } from "interfaces/software";

import Modal from "components/Modal";
import Button from "components/buttons/Button";
Expand All @@ -11,7 +11,7 @@ const baseClass = "automatic-install-modal";

interface IPoliciesListItemProps {
teamId: number;
policy: ISoftwarePackagePolicy;
policy: ISoftwareInstallPolicy;
}

const PoliciesListItem = ({ teamId, policy }: IPoliciesListItemProps) => {
Expand All @@ -24,7 +24,7 @@ const PoliciesListItem = ({ teamId, policy }: IPoliciesListItemProps) => {

interface IPoliciesListProps {
teamId: number;
policies: ISoftwarePackagePolicy[];
policies: ISoftwareInstallPolicy[];
}

const PoliciesList = ({ teamId, policies }: IPoliciesListProps) => {
Expand All @@ -39,7 +39,7 @@ const PoliciesList = ({ teamId, policies }: IPoliciesListProps) => {

interface IAutomaticInstallModalProps {
teamId: number;
policies: ISoftwarePackagePolicy[];
policies: ISoftwareInstallPolicy[];
onExit: () => void;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ const DELETE_SW_INSTALLED_DURING_SETUP_ERROR_MSG =
interface IDeleteSoftwareModalProps {
softwareId: number;
teamId: number;
softwarePackageName?: string;
softwareInstallerName?: string;
onExit: () => void;
onSuccess: () => void;
}

const DeleteSoftwareModal = ({
softwareId,
teamId,
softwarePackageName,
softwareInstallerName,
onExit,
onSuccess,
}: IDeleteSoftwareModalProps) => {
Expand All @@ -36,7 +36,7 @@ const DeleteSoftwareModal = ({
const onDeleteSoftware = useCallback(async () => {
setIsDeleting(true);
try {
await softwareAPI.deleteSoftwarePackage(softwareId, teamId);
await softwareAPI.deleteSoftwareInstaller(softwareId, teamId);
renderFlash("success", "Software deleted successfully!");
onSuccess();
} catch (error) {
Expand Down Expand Up @@ -64,9 +64,9 @@ const DeleteSoftwareModal = ({
<p>
Software won&apos;t be uninstalled from existing hosts, but any
pending installs and uninstalls{" "}
{softwarePackageName ? (
{softwareInstallerName ? (
<>
for <b> {softwarePackageName}</b>{" "}
for <b> {softwareInstallerName}</b>{" "}
</>
) : (
""
Expand Down
Loading
Loading