Add UI tooltips for errors related to certificates feature in host MDM profiles (#27252)

This commit is contained in:
Sarah Gillespie 2025-03-19 10:04:03 -05:00 committed by GitHub
parent 84892741dd
commit dd99760ee6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 163 additions and 22 deletions

View file

@ -100,4 +100,64 @@ describe("OSSettingsErrorCell", () => {
expect(screen.getByText(/Learn more/)).toBeInTheDocument();
expect(screen.getByText(/Learn more/).tagName.toLowerCase()).toBe("a");
});
it("renders a formatted tooltip when the error message matches custom scep error patern", () => {
render(
<OSSettingsErrorCell
canResendProfiles
hostId={1}
profile={createMockHostMdmProfile({
status: "failed",
detail: `Fleet couldnt populate $FLEET_VAR_CUSTOM_SCEP_URL_SCEP_WIFI because SCEP_WIFI certificate authority doesnt exist.`,
})}
/>
);
expect(
screen.getByText("Settings > Integrations > Certificates")
).toBeInTheDocument();
expect(
screen.getByText(/add it and resend the configuration profile/)
).toBeInTheDocument();
});
it("renders a formatted tooltip when the error message matches digicert guid patern", () => {
render(
<OSSettingsErrorCell
canResendProfiles
hostId={1}
profile={createMockHostMdmProfile({
status: "failed",
detail: `Couldnt get certificate from DigiCert. The "profile_id" configured in DIGICERT_WIFI certificate authority doesnt exist.`,
})}
/>
);
expect(
screen.getByText("Settings > Integrations > Certificates")
).toBeInTheDocument();
expect(screen.getByText(/correct it and resend/)).toBeInTheDocument();
expect(screen.getByText("DIGICERT_WIFI")).toBeInTheDocument();
expect(screen.getByText("Profile GUID")).toBeInTheDocument();
});
it("renders a formatted tooltip when the error message matches digicert token patern", () => {
render(
<OSSettingsErrorCell
canResendProfiles
hostId={1}
profile={createMockHostMdmProfile({
status: "failed",
detail: `Couldnt get certificate from DigiCert. The API token configured in DIGICERT_TEST certificate authority is invalid.`,
})}
/>
);
expect(
screen.getByText("Settings > Integrations > Certificates")
).toBeInTheDocument();
expect(screen.getByText(/correct it and resend/)).toBeInTheDocument();
expect(screen.getByText("DIGICERT_TEST")).toBeInTheDocument();
expect(screen.getByText("API token")).toBeInTheDocument();
});
});

View file

@ -6,6 +6,8 @@ import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants";
import hostAPI from "services/entities/hosts";
import { NotificationContext } from "context/notification";
import { IHostMdmProfile } from "interfaces/mdm";
import TooltipTruncatedTextCell from "components/TableContainer/DataTable/TooltipTruncatedTextCell";
import Button from "components/buttons/Button";
import Icon from "components/Icon";
@ -42,12 +44,99 @@ const RefetchButton = ({ isFetching, onClick }: IRefetchButtonProps) => {
);
};
/**
* formatDetailCertificateError generates the formatted detail for certain errors related to
* certificate profiles. It return a JSX element with the formatted message or null if
* the detail does not match any of the expected patterns.
*/
const formatDetailCertificateError = (detail: IHostMdmProfile["detail"]) => {
const matchTokenErr = detail.match(
/get certificate from (?:DigiCert|Digicert|digicert).*token configured in (?<ca>.*) certificate authority is invalid/
);
if (matchTokenErr?.groups) {
return (
<>
Couldn&apos;t get certificate from DigiCert. The <b>API token</b>{" "}
configured in <b>{matchTokenErr.groups.ca}</b> certificate authority is
invalid. Please go to{" "}
<b>
Settings {">"} Integrations {">"} Certificates
</b>
, correct it and resend.
</>
);
}
const matchProfileIdErr = detail.match(
/get certificate from (?:DigiCert|Digicert|digicert).*profile_id.*configured in (?<ca>.*) certificate authority does(?:n.t| not) exist/
);
if (matchProfileIdErr?.groups) {
return (
<>
Couldn&apos;t get certificate from DigiCert. The <b>Profile GUID</b>{" "}
configured in <b>{matchProfileIdErr.groups.ca}</b> certificate authority
doesn&apos;t exist. Please go to{" "}
<b>
Settings {">"} Integrations {">"} Certificates
</b>
, correct it and resend.
</>
);
}
const matchFleetVarErr = detail.match(
/populate (?<field>.*) because (?<ca>.*) certificate authority does(?:n.t| not) exist/
);
if (matchFleetVarErr?.groups) {
return (
<>
Fleet couldn&apos;t populate {matchFleetVarErr.groups.field} because{" "}
<b>{matchFleetVarErr.groups.ca}</b> certificate authority doesn&apos;t
exist. Please go to{" "}
<b>
Settings {">"} Integrations {">"} Certificates
</b>
, add it and resend the configuration profile.
</>
);
}
return null;
};
/**
* formatDetailIdpEmailError generates the formatted detail for certain errors related to
* host IdP email profiles. It returns a JSX element with the formatted message or null if
* the detail does not match any of the expected patterns.
*/
const formatDetailIdpEmailError = (detail: IHostMdmProfile["detail"]) => {
if (detail.includes("There is no IdP email for this host.")) {
return (
<>
There is no IdP email for this host.
<br />
Fleet couldn&apos;t populate
<br />
$FLEET_VAR_HOST_END_USER_EMAIL_IDP.
<br />
<CustomLink
text="Learn more"
url="https://fleetdm.com/learn-more-about/idp-email"
newTab
variant="tooltip-link"
/>
</>
);
}
return null;
};
/**
* generates the formatted tooltip for the error column.
* the expected format of the error string is:
* "key1: value1, key2: value2, key3: value3"
*/
const generateFormattedTooltip = (detail: string) => {
const formatDetailWindowsProfile = (detail: string) => {
const keyValuePairs = detail.split(/, */);
const formattedElements: JSX.Element[] = [];
@ -90,31 +179,23 @@ const generateErrorTooltip = (
) => {
if (profile.status !== "failed") return null;
// Special case for creating UI link
if (profile.detail.includes("There is no IdP email for this host.")) {
return (
<>
There is no IdP email for this host.
<br />
Fleet couldn&apos;t populate
<br />
$FLEET_VAR_HOST_END_USER_EMAIL_IDP.
<br />
<CustomLink
text="Learn more"
url="https://fleetdm.com/learn-more-about/idp-email"
newTab
variant="tooltip-link"
/>
</>
);
// Special case to handle IdP email errors
const idpEmailError = formatDetailIdpEmailError(profile.detail);
if (idpEmailError) {
return idpEmailError;
}
if (profile.platform !== "windows") {
return cellValue;
// Special case to handle certificate profile errors
const certificateError = formatDetailCertificateError(profile.detail);
if (certificateError) {
return certificateError;
}
return generateFormattedTooltip(profile.detail);
if (profile.platform === "windows") {
return formatDetailWindowsProfile(profile.detail);
}
return cellValue;
};
interface IOSSettingsErrorCellProps {