mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 08:55:24 +00:00
Manage Policies Page: New policy modal (#3108)
This commit is contained in:
parent
5a2ed6f395
commit
eba5d1b1b6
1
changes/issue-2594-add-policy-modal-revamp
Normal file
1
changes/issue-2594-add-policy-modal-revamp
Normal file
@ -0,0 +1 @@
|
||||
* In the Add a policy modal, users are prompted to add common policies or create a new one
|
@ -1,5 +1,5 @@
|
||||
.input-field {
|
||||
line-height: 34px;
|
||||
line-height: 1.5;
|
||||
background-color: $ui-light-grey;
|
||||
border: solid 1px $ui-fleet-blue-15;
|
||||
border-radius: 4px;
|
||||
|
@ -48,3 +48,11 @@ export interface IPolicyFormData {
|
||||
query?: string | number | boolean | any[] | undefined;
|
||||
team_id?: number;
|
||||
}
|
||||
|
||||
export interface IPolicyNew {
|
||||
id?: number;
|
||||
name: string;
|
||||
description: string;
|
||||
query: string;
|
||||
resolution: string;
|
||||
}
|
||||
|
@ -100,6 +100,12 @@ interface IHostResponse {
|
||||
host: IHost;
|
||||
}
|
||||
|
||||
const TAGGED_TEMPLATES = {
|
||||
queryByHostRoute: (hostId: number | undefined | null) => {
|
||||
return `${hostId ? `?host_ids=${hostId}` : ""}`;
|
||||
},
|
||||
};
|
||||
|
||||
const HostDetailsPage = ({
|
||||
router,
|
||||
params: { host_id },
|
||||
@ -117,6 +123,7 @@ const HostDetailsPage = ({
|
||||
setLastEditedQueryName,
|
||||
setLastEditedQueryDescription,
|
||||
setLastEditedQueryBody,
|
||||
setLastEditedQueryResolution,
|
||||
setPolicyTeamId,
|
||||
} = useContext(PolicyContext);
|
||||
const canTransferTeam =
|
||||
@ -401,6 +408,7 @@ const HostDetailsPage = ({
|
||||
"Returns yes or no for detecting operating system and version"
|
||||
);
|
||||
setLastEditedQueryBody(osPolicy);
|
||||
setLastEditedQueryResolution("");
|
||||
router.replace(NEW_POLICY);
|
||||
};
|
||||
|
||||
@ -453,6 +461,17 @@ const HostDetailsPage = ({
|
||||
return router.push(`${PATHS.MANAGE_HOSTS}/labels/${label.id}`);
|
||||
};
|
||||
|
||||
const onQueryHostCustom = () => {
|
||||
router.push(PATHS.NEW_QUERY + TAGGED_TEMPLATES.queryByHostRoute(host?.id));
|
||||
};
|
||||
|
||||
const onQueryHostSaved = (selectedQuery: IQuery) => {
|
||||
router.push(
|
||||
PATHS.EDIT_QUERY(selectedQuery) +
|
||||
TAGGED_TEMPLATES.queryByHostRoute(host?.id)
|
||||
);
|
||||
};
|
||||
|
||||
const onTransferHostSubmit = async (team: ITeam) => {
|
||||
const teamId = typeof team.id === "number" ? team.id : null;
|
||||
|
||||
@ -1303,14 +1322,15 @@ const HostDetailsPage = ({
|
||||
</TabsWrapper>
|
||||
|
||||
{showDeleteHostModal && renderDeleteHostModal()}
|
||||
{showQueryHostModal && (
|
||||
{showQueryHostModal && host && (
|
||||
<SelectQueryModal
|
||||
host={host}
|
||||
onCancel={() => setShowQueryHostModal(false)}
|
||||
queries={fleetQueries}
|
||||
dispatch={dispatch}
|
||||
queries={fleetQueries || []}
|
||||
queryErrors={fleetQueriesError}
|
||||
isOnlyObserver={isOnlyObserver}
|
||||
onQueryHostCustom={onQueryHostCustom}
|
||||
onQueryHostSaved={onQueryHostSaved}
|
||||
/>
|
||||
)}
|
||||
{!!host && showTransferHostModal && (
|
||||
|
@ -1,58 +1,48 @@
|
||||
import React, { useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { push } from "react-router-redux";
|
||||
import React, { useState, useCallback } from "react";
|
||||
|
||||
import { filter, includes } from "lodash";
|
||||
|
||||
import PATHS from "router/paths";
|
||||
import queryInterface from "interfaces/query";
|
||||
import hostInterface from "interfaces/host";
|
||||
import { IHost } from "interfaces/host";
|
||||
import { IQuery } from "interfaces/query";
|
||||
|
||||
import Button from "components/buttons/Button";
|
||||
import Modal from "components/Modal";
|
||||
// @ts-ignore
|
||||
import InputField from "components/forms/fields/InputField";
|
||||
|
||||
import OpenNewTabIcon from "../../../../../assets/images/open-new-tab-12x12@2x.png";
|
||||
import ErrorIcon from "../../../../../assets/images/icon-error-16x16@2x.png";
|
||||
|
||||
export interface ISelectQueryModalProps {
|
||||
host: IHost;
|
||||
onCancel: () => void;
|
||||
onQueryHostCustom: () => void;
|
||||
onQueryHostSaved: (selectedQuery: IQuery) => void;
|
||||
queries: IQuery[] | [];
|
||||
queryErrors: any | null;
|
||||
isOnlyObserver: boolean | undefined;
|
||||
}
|
||||
|
||||
const baseClass = "select-query-modal";
|
||||
|
||||
const onQueryHostCustom = (host, dispatch) => {
|
||||
return dispatch(
|
||||
push({
|
||||
pathname: PATHS.NEW_QUERY,
|
||||
query: { host_ids: [host.id] },
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const onQueryHostSaved = (host, selectedQuery, dispatch) => {
|
||||
return dispatch(
|
||||
push({
|
||||
pathname: PATHS.EDIT_QUERY(selectedQuery),
|
||||
query: { host_ids: [host.id] },
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const SelectQueryModal = ({
|
||||
host,
|
||||
onCancel,
|
||||
dispatch,
|
||||
onQueryHostCustom,
|
||||
onQueryHostSaved,
|
||||
queries,
|
||||
queryErrors,
|
||||
isOnlyObserver,
|
||||
}) => {
|
||||
}: ISelectQueryModalProps) => {
|
||||
let queriesAvailableToRun = queries;
|
||||
|
||||
const [queriesFilter, setQueriesFilter] = useState("");
|
||||
|
||||
if (isOnlyObserver) {
|
||||
queriesAvailableToRun = queries.filter(
|
||||
(query) => query.observer_can_run === true
|
||||
);
|
||||
}
|
||||
|
||||
const [queriesFilter, setQueriesFilter] = useState("");
|
||||
|
||||
const getQueries = () => {
|
||||
if (!queriesFilter) {
|
||||
return queriesAvailableToRun;
|
||||
@ -71,10 +61,21 @@ const SelectQueryModal = ({
|
||||
});
|
||||
};
|
||||
|
||||
const onFilterQueries = useCallback(
|
||||
(filterString: string): void => {
|
||||
setQueriesFilter(filterString);
|
||||
},
|
||||
[setQueriesFilter]
|
||||
);
|
||||
|
||||
const queriesFiltered = getQueries();
|
||||
|
||||
const queriesCount = queriesFiltered.length;
|
||||
|
||||
const customQueryButton = () => {
|
||||
return (
|
||||
<Button
|
||||
onClick={() => onQueryHostCustom(host, dispatch)}
|
||||
onClick={() => onQueryHostCustom()}
|
||||
variant="brand"
|
||||
className={`${baseClass}__custom-query-button`}
|
||||
>
|
||||
@ -83,16 +84,7 @@ const SelectQueryModal = ({
|
||||
);
|
||||
};
|
||||
|
||||
const onFilterQueries = (event) => {
|
||||
setQueriesFilter(event);
|
||||
return false;
|
||||
};
|
||||
|
||||
const queriesFiltered = getQueries();
|
||||
|
||||
const queriesCount = queriesFiltered.length;
|
||||
|
||||
const results = () => {
|
||||
const results = (): JSX.Element => {
|
||||
if (queryErrors) {
|
||||
return (
|
||||
<div className={`${baseClass}__no-queries`}>
|
||||
@ -137,10 +129,12 @@ const SelectQueryModal = ({
|
||||
key={query.id}
|
||||
variant="unstyled-modal-query"
|
||||
className="modal-query-button"
|
||||
onClick={() => onQueryHostSaved(host, query, dispatch)}
|
||||
onClick={() => onQueryHostSaved(query)}
|
||||
>
|
||||
<span className="info__header">{query.name}</span>
|
||||
<span className="info__data">{query.description}</span>
|
||||
<>
|
||||
<span className="info__header">{query.name}</span>
|
||||
<span className="info__data">{query.description}</span>
|
||||
</>
|
||||
</Button>
|
||||
);
|
||||
});
|
||||
@ -198,7 +192,7 @@ const SelectQueryModal = ({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
return <></>;
|
||||
};
|
||||
|
||||
return (
|
||||
@ -212,13 +206,4 @@ const SelectQueryModal = ({
|
||||
);
|
||||
};
|
||||
|
||||
SelectQueryModal.propTypes = {
|
||||
dispatch: PropTypes.func,
|
||||
host: hostInterface,
|
||||
queries: PropTypes.arrayOf(queryInterface),
|
||||
onCancel: PropTypes.func,
|
||||
queryErrors: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
isOnlyObserver: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default SelectQueryModal;
|
@ -25,6 +25,13 @@
|
||||
padding: $pad-xxlarge;
|
||||
border-radius: $pad-small;
|
||||
|
||||
a {
|
||||
font-size: $x-small;
|
||||
color: $core-vibrant-blue;
|
||||
font-weight: $bold;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
|
||||
|
@ -31,6 +31,7 @@ import InfoBanner from "components/InfoBanner/InfoBanner";
|
||||
import IconToolTip from "components/IconToolTip";
|
||||
import TeamsDropdown from "components/TeamsDropdown";
|
||||
import PoliciesListWrapper from "./components/PoliciesListWrapper";
|
||||
import AddPolicyModal from "./components/AddPolicyModal";
|
||||
import RemovePoliciesModal from "./components/RemovePoliciesModal";
|
||||
|
||||
const baseClass = "manage-policies-page";
|
||||
@ -72,6 +73,7 @@ const ManagePolicyPage = (managePoliciesPageProps: {
|
||||
setLastEditedQueryName,
|
||||
setLastEditedQueryDescription,
|
||||
setLastEditedQueryBody,
|
||||
setLastEditedQueryResolution,
|
||||
setPolicyTeamId,
|
||||
} = useContext(PolicyContext);
|
||||
|
||||
@ -121,6 +123,7 @@ const ManagePolicyPage = (managePoliciesPageProps: {
|
||||
const [selectedPolicyIds, setSelectedPolicyIds] = useState<
|
||||
number[] | never[]
|
||||
>([]);
|
||||
const [showAddPolicyModal, setShowAddPolicyModal] = useState(false);
|
||||
const [showRemovePoliciesModal, setShowRemovePoliciesModal] = useState(false);
|
||||
const [showInheritedPolicies, setShowInheritedPolicies] = useState(false);
|
||||
const [updateInterval, setUpdateInterval] = useState<string>(
|
||||
@ -180,6 +183,8 @@ const ManagePolicyPage = (managePoliciesPageProps: {
|
||||
setPolicyTeamId(id);
|
||||
};
|
||||
|
||||
const toggleAddPolicyModal = () => setShowAddPolicyModal(!showAddPolicyModal);
|
||||
|
||||
const toggleRemovePoliciesModal = () =>
|
||||
setShowRemovePoliciesModal(!showRemovePoliciesModal);
|
||||
|
||||
@ -190,7 +195,8 @@ const ManagePolicyPage = (managePoliciesPageProps: {
|
||||
setLastEditedQueryName("");
|
||||
setLastEditedQueryDescription("");
|
||||
setLastEditedQueryBody(DEFAULT_POLICY.query);
|
||||
router.push(PATHS.NEW_POLICY);
|
||||
setLastEditedQueryResolution("");
|
||||
toggleAddPolicyModal();
|
||||
};
|
||||
|
||||
const onRemovePoliciesClick = (selectedTableIds: number[]): void => {
|
||||
@ -362,7 +368,7 @@ const ManagePolicyPage = (managePoliciesPageProps: {
|
||||
<div className={`${baseClass}__action-button-container`}>
|
||||
<Button
|
||||
variant="brand"
|
||||
className={`${baseClass}__add-policy-btn`}
|
||||
className={`${baseClass}__select-policy-button`}
|
||||
onClick={onAddPolicyClick}
|
||||
>
|
||||
Add a policy
|
||||
@ -411,6 +417,7 @@ const ManagePolicyPage = (managePoliciesPageProps: {
|
||||
policiesList={teamPolicies}
|
||||
isLoading={isLoadingTeamPolicies}
|
||||
onRemovePoliciesClick={onRemovePoliciesClick}
|
||||
toggleAddPolicyModal={toggleAddPolicyModal}
|
||||
canAddOrRemovePolicy={canAddOrRemovePolicy(
|
||||
currentUser,
|
||||
selectedTeamId
|
||||
@ -426,6 +433,7 @@ const ManagePolicyPage = (managePoliciesPageProps: {
|
||||
policiesList={globalPolicies}
|
||||
isLoading={isLoadingGlobalPolicies}
|
||||
onRemovePoliciesClick={onRemovePoliciesClick}
|
||||
toggleAddPolicyModal={toggleAddPolicyModal}
|
||||
canAddOrRemovePolicy={canAddOrRemovePolicy(
|
||||
currentUser,
|
||||
selectedTeamId
|
||||
@ -475,6 +483,14 @@ const ManagePolicyPage = (managePoliciesPageProps: {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{showAddPolicyModal && (
|
||||
<AddPolicyModal
|
||||
onCancel={toggleAddPolicyModal}
|
||||
router={router}
|
||||
teamId={selectedTeamId}
|
||||
teamName={selectedTeamData?.name}
|
||||
/>
|
||||
)}
|
||||
{showRemovePoliciesModal && (
|
||||
<RemovePoliciesModal
|
||||
onCancel={toggleRemovePoliciesModal}
|
||||
|
@ -0,0 +1,84 @@
|
||||
import React, { useContext } from "react";
|
||||
import { Link } from "react-router";
|
||||
import PATHS from "router/paths";
|
||||
|
||||
import { DEFAULT_POLICY, DEFAULT_POLICIES } from "utilities/constants";
|
||||
|
||||
import { IPolicyNew } from "interfaces/policy";
|
||||
|
||||
import { PolicyContext } from "context/policy";
|
||||
|
||||
import Button from "components/buttons/Button";
|
||||
import Modal from "components/Modal";
|
||||
|
||||
export interface IAddPolicyModalProps {
|
||||
onCancel: () => void;
|
||||
router: any;
|
||||
teamId: number;
|
||||
teamName?: string;
|
||||
}
|
||||
|
||||
const baseClass = "add-policy-modal";
|
||||
|
||||
const AddPolicyModal = ({
|
||||
onCancel,
|
||||
router,
|
||||
teamId,
|
||||
teamName,
|
||||
}: IAddPolicyModalProps) => {
|
||||
const {
|
||||
setLastEditedQueryName,
|
||||
setLastEditedQueryDescription,
|
||||
setLastEditedQueryBody,
|
||||
setLastEditedQueryResolution,
|
||||
setPolicyTeamId,
|
||||
} = useContext(PolicyContext);
|
||||
|
||||
const onAddPolicy = (selectedPolicy: IPolicyNew) => {
|
||||
teamName
|
||||
? setLastEditedQueryName(`${selectedPolicy.name} (${teamName})`)
|
||||
: setLastEditedQueryName(selectedPolicy.name);
|
||||
setLastEditedQueryDescription(selectedPolicy.description);
|
||||
setLastEditedQueryBody(selectedPolicy.query);
|
||||
setLastEditedQueryResolution(selectedPolicy.resolution);
|
||||
setPolicyTeamId(teamId);
|
||||
router.push(PATHS.NEW_POLICY);
|
||||
};
|
||||
|
||||
const policiesAvailable = DEFAULT_POLICIES.map((policy) => {
|
||||
return (
|
||||
<Button
|
||||
key={policy.key}
|
||||
variant="unstyled-modal-query"
|
||||
className="modal-policy-button"
|
||||
onClick={() => onAddPolicy(policy)}
|
||||
>
|
||||
<>
|
||||
<span className="info__header">{policy.name}</span>
|
||||
<span className="info__data">{policy.description}</span>
|
||||
</>
|
||||
</Button>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="Add a policy"
|
||||
onExit={onCancel}
|
||||
className={`${baseClass}__modal`}
|
||||
>
|
||||
<>
|
||||
Choose a policy template to get started or{" "}
|
||||
<Link to={PATHS.NEW_POLICY} className={`${baseClass}__back-link`}>
|
||||
create your own policy
|
||||
</Link>
|
||||
.
|
||||
<div className={`${baseClass}__policy-selection`}>
|
||||
{policiesAvailable}
|
||||
</div>
|
||||
</>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddPolicyModal;
|
@ -0,0 +1,59 @@
|
||||
.add-policy-modal {
|
||||
#error-icon {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
#new-tab-icon {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: $x-small;
|
||||
color: $core-vibrant-blue;
|
||||
font-weight: $bold;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&__modal {
|
||||
@include position(absolute, 22px null null null);
|
||||
background-color: $core-white;
|
||||
width: 658px;
|
||||
padding: $pad-xxlarge;
|
||||
border-radius: $pad-small;
|
||||
|
||||
a {
|
||||
font-size: $x-small;
|
||||
color: $core-vibrant-blue;
|
||||
font-weight: $bold;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
|
||||
&__header {
|
||||
display: block;
|
||||
color: $core-fleet-black;
|
||||
font-weight: $bold;
|
||||
font-size: $x-small;
|
||||
text-align: left;
|
||||
}
|
||||
&__data {
|
||||
display: block;
|
||||
color: $core-fleet-black;
|
||||
font-weight: normal;
|
||||
font-size: $x-small;
|
||||
text-align: left;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__policy-selection {
|
||||
padding: $pad-large 0;
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
export { default } from "./AddPolicyModal";
|
@ -27,6 +27,7 @@ interface IPoliciesListWrapperProps {
|
||||
canAddOrRemovePolicy?: boolean;
|
||||
tableType?: string;
|
||||
selectedTeamData: ITeam | undefined;
|
||||
toggleAddPolicyModal?: () => void;
|
||||
}
|
||||
|
||||
const PoliciesListWrapper = ({
|
||||
@ -37,6 +38,7 @@ const PoliciesListWrapper = ({
|
||||
canAddOrRemovePolicy,
|
||||
tableType,
|
||||
selectedTeamData,
|
||||
toggleAddPolicyModal,
|
||||
}: IPoliciesListWrapperProps): JSX.Element => {
|
||||
const { MANAGE_HOSTS } = paths;
|
||||
|
||||
|
@ -33,15 +33,19 @@ const NewPolicyModal = ({
|
||||
onCreatePolicy,
|
||||
setIsNewPolicyModalOpen,
|
||||
}: INewPolicyModalProps): JSX.Element => {
|
||||
const { lastEditedQueryName, lastEditedQueryDescription } = useContext(
|
||||
PolicyContext
|
||||
);
|
||||
const {
|
||||
lastEditedQueryName,
|
||||
lastEditedQueryDescription,
|
||||
lastEditedQueryResolution,
|
||||
} = useContext(PolicyContext);
|
||||
|
||||
const [name, setName] = useState<string>(lastEditedQueryName);
|
||||
const [description, setDescription] = useState<string>(
|
||||
lastEditedQueryDescription
|
||||
);
|
||||
const [resolution, setResolution] = useState<string>("");
|
||||
const [resolution, setResolution] = useState<string>(
|
||||
lastEditedQueryResolution
|
||||
);
|
||||
const [errors, setErrors] = useState<{ [key: string]: string }>({});
|
||||
|
||||
useDeepEffect(() => {
|
||||
|
@ -41,6 +41,7 @@ const QueryPage = ({
|
||||
location: { query: URLQuerySearch },
|
||||
}: IQueryPageProps): JSX.Element => {
|
||||
const queryIdForEdit = paramsQueryId ? parseInt(paramsQueryId, 10) : null;
|
||||
|
||||
const {
|
||||
isGlobalAdmin,
|
||||
isGlobalMaintainer,
|
||||
|
@ -11,6 +11,74 @@ export enum PolicyResponse {
|
||||
export const DEFAULT_GRAVATAR_LINK =
|
||||
"https://fleetdm.com/images/permanent/icon-avatar-default-128x128-2x.png";
|
||||
|
||||
export const DEFAULT_POLICIES = [
|
||||
{
|
||||
key: 1,
|
||||
query: `SELECT 1 FROM disk_encryption WHERE user_uuid IS NOT "" AND filevault_status = 'on' LIMIT 1`,
|
||||
name: "Is Filevault enabled on macOS devices?",
|
||||
description:
|
||||
"Checks to make sure that the Filevault feature is enabled on macOS devices.",
|
||||
resolution:
|
||||
"Choose Apple menu > System Preferences, then click Security & Privacy. Click the FileVault tab. Click the Lock icon, then enter an administrator name and password. Click Turn On FileVault.",
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
query: "SELECT 1 FROM gatekeeper WHERE assessments_enabled = 1",
|
||||
name: "Is Gatekeeper enabled on macOS devices?",
|
||||
description:
|
||||
"Checks to make sure that the Gatekeeper feature is enabled on macOS devices. Gatekeeper tries to ensure only trusted software is run on a mac machine.",
|
||||
resolution:
|
||||
"On the failing device, run the following command in the Terminal app: /usr/sbin / spctl--master- enable",
|
||||
},
|
||||
{
|
||||
key: 3,
|
||||
query: "SELECT 1 FROM bitlocker_info WHERE protection_status = 1;",
|
||||
name: "Is disk encryption enabled on Windows devices?",
|
||||
description:
|
||||
"Checks to make sure that device encryption is enabled on Windows devices.",
|
||||
resolution:
|
||||
"Option 1: Select the Start button. Select Settings > Update & Security > Device encryption. If Device encryption doesn't appear, skip to Option 2. If device encryption is turned off, select Turn on. Option 2: Select the Start button. Under Windows System, select Control Panel. Select System and Security. Under BitLocker Drive Encryption, select Manage BitLocker. Select Turn on BitLocker and then follow the instructions.",
|
||||
},
|
||||
{
|
||||
key: 4,
|
||||
query:
|
||||
"SELECT 1 FROM sip_config WHERE config_flag = 'sip' AND enabled = 1;",
|
||||
name: "Is System Integrity Protection (SIP) enabled on macOS devices?",
|
||||
description: "Checks to make sure that the SIP is enabled.",
|
||||
resolution:
|
||||
"On the failing device, run the following command in the Terminal app: /usr/sbin/spctl --master-enable",
|
||||
},
|
||||
{
|
||||
key: 5,
|
||||
query:
|
||||
"SELECT 1 FROM managed_policies WHERE domain = 'com.apple.loginwindow' AND name = 'com.apple.login.mcx.DisableAutoLoginClient' AND value = 1 LIMIT 1",
|
||||
name: "Is automatic login disabled on macOS devices?",
|
||||
description:
|
||||
"Required: You’re already enforcing a policy via Moble Device Management (MDM). Checks to make sure that the device user cannot log in to the device without a password. It’s good practice to have both this policy and the “Is Filevault enabled on macOS devices?” policy enabled.",
|
||||
resolution:
|
||||
"The following example profile includes a setting to disable automatic login: https://github.com/gregneagle/profiles/blob/fecc73d66fa17b6fa78b782904cb47cdc1913aeb/loginwindow.mobileconfig#L64-L65",
|
||||
},
|
||||
{
|
||||
key: 6,
|
||||
query:
|
||||
"SELECT 1 FROM managed_policies WHERE domain = 'com.apple.MCX' AND name = 'DisableGuestAccount' AND value = 0 LIMIT 1;",
|
||||
name: "Are guest users not activated on macOS devices?",
|
||||
description:
|
||||
"Required: You’re already enforcing a policy via Moble Device Management (MDM). Checks to make sure that guest accounts cannot be used to log in to the device without a password.",
|
||||
resolution:
|
||||
"The following example profile includes a setting to disable automatic login: https://github.com/gregneagle/profiles/blob/fecc73d66fa17b6fa78b782904cb47cdc1913aeb/loginwindow.mobileconfig#L68-L71",
|
||||
},
|
||||
{
|
||||
key: 7,
|
||||
query:
|
||||
"SELECT 1 FROM managed_policies WHERE domain = 'com.apple.Terminal' AND name = 'SecureKeyboardEntry' AND value=1 LIMIT 1;",
|
||||
name: "Is secure keyboard entry enabled on macOS devices?",
|
||||
description:
|
||||
"Required: You’re already enforcing a policy via Moble Device Management (MDM). Checks to make sure that the Secure Keyboard Entry setting is enabled.",
|
||||
resolution: "",
|
||||
},
|
||||
];
|
||||
|
||||
export const FREQUENCY_DROPDOWN_OPTIONS = [
|
||||
{ value: 900, label: "Every 15 minutes" },
|
||||
{ value: 3600, label: "Every hour" },
|
||||
|
Loading…
Reference in New Issue
Block a user