Fix cert sign not showing under certain instances (#6908)

This commit is contained in:
Anthony Stirling
2026-07-07 22:39:57 +01:00
committed by GitHub
parent 105af51100
commit f703a67817
2 changed files with 36 additions and 7 deletions
@@ -59,7 +59,7 @@ async function mockHardwareEndpoints(page: Page) {
}
test.describe("CertSign tool - certificate source model", () => {
test("renders, accepts a PDF, and defaults to upload when no other sources exist", async ({
test("skips the redundant source step and goes straight to certificate format when Upload is the only source", async ({
page,
}) => {
await page.route("**/api/v1/security/cert-sign", (route) =>
@@ -76,12 +76,19 @@ test.describe("CertSign tool - certificate source model", () => {
await uploadFiles(page, SAMPLE_PDF);
await expect(page).toHaveURL(/\/cert-sign/);
// With no server/hardware sources, the picker collapses to a hint and the
// flow proceeds in the default MANUAL (upload) mode — no lone Upload CTA.
// With no server cert or hardware token there is nothing to choose, so the
// whole "Certificate source" step is hidden and the format picker shows directly.
await expect(
page.getByText(/no other certificate sources are available/i).first(),
page.getByRole("button", { name: /pkcs12/i }).first(),
).toBeVisible({ timeout: 10_000 });
await expect(page.getByRole("button", { name: /^upload$/i })).toHaveCount(
await expect(page.getByText(/certificate source/i)).toHaveCount(0);
await expect(
page.getByText(/no other certificate sources are available/i),
).toHaveCount(0);
await expect(
page.getByRole("button", { name: /this device/i }),
).toHaveCount(0);
await expect(page.getByRole("button", { name: /^server$/i })).toHaveCount(
0,
);
});
@@ -93,9 +100,9 @@ test.describe("CertSign tool - certificate source model", () => {
await page.waitForLoadState("domcontentloaded");
await uploadFiles(page, SAMPLE_PDF);
// No alternative sources: the picker is a hint, and hardware is never offered.
// No alternative sources: the source step is hidden, and hardware is never offered.
await expect(
page.getByText(/no other certificate sources are available/i).first(),
page.getByRole("button", { name: /pkcs12/i }).first(),
).toBeVisible({ timeout: 10_000 });
await expect(
page.getByRole("button", { name: /this device/i }),
@@ -1,5 +1,7 @@
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { createToolFlow } from "@app/components/tools/shared/createToolFlow";
import { useAppConfig } from "@app/contexts/AppConfigContext";
import CertificateTypeSettings from "@app/components/tools/certSign/CertificateTypeSettings";
import CertificateFormatSettings from "@app/components/tools/certSign/CertificateFormatSettings";
import CertificateFilesSettings from "@app/components/tools/certSign/CertificateFilesSettings";
@@ -23,6 +25,25 @@ const CertSign = (props: BaseToolProps) => {
props,
);
const { config } = useAppConfig();
// "Upload" is always available; the source chooser is only meaningful when a
// server certificate or a hardware token gives the user an actual alternative.
const hasCertSourceChoice =
(config?.serverCertificateEnabled ?? false) ||
(config?.hardwareSigningAvailable ?? false);
// With Upload as the only source, keep signMode on MANUAL even if a saved
// automation set AUTO/DEVICE, so the hidden source step can't strand the flow.
useEffect(() => {
if (!hasCertSourceChoice && base.params.parameters.signMode !== "MANUAL") {
base.params.updateParameter("signMode", "MANUAL");
}
}, [
hasCertSourceChoice,
base.params.parameters.signMode,
base.params.updateParameter,
]);
const certTypeTips = useCertificateTypeTips();
const appearanceTips = useSignatureAppearanceTips();
const signModeTips = useSignModeTips();
@@ -63,6 +84,7 @@ const CertSign = (props: BaseToolProps) => {
steps: [
{
title: t("certSign.source.stepTitle", "Certificate source"),
isVisible: hasCertSourceChoice,
isCollapsed: base.settingsCollapsed,
onCollapsedClick: base.settingsCollapsed
? base.handleSettingsReset