mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-17 00:44:17 +00:00
fix(ui): reuse provider secret on credentials retry
- Switch credentials step to update flow whenever a provider secret exists - Persist loaded provider secret id during connection test step - Add regression tests for add->retry flow after failed role authentication
This commit is contained in:
4 files changed
+155
-6
No files matched your search
@@ -0,0 +1,79 @@
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { useProviderWizardStore } from "@/store/provider-wizard/store";
|
||||
import { PROVIDER_WIZARD_MODE } from "@/types/provider-wizard";
|
||||
|
||||
import { CredentialsStep } from "./credentials-step";
|
||||
|
||||
vi.mock("../../workflow/forms", () => ({
|
||||
AddViaCredentialsForm: () => <div>add-via-credentials-form</div>,
|
||||
AddViaRoleForm: () => <div>add-via-role-form</div>,
|
||||
UpdateViaCredentialsForm: () => <div>update-via-credentials-form</div>,
|
||||
UpdateViaRoleForm: () => <div>update-via-role-form</div>,
|
||||
}));
|
||||
|
||||
vi.mock("../../workflow/forms/select-credentials-type/aws", () => ({
|
||||
SelectViaAWS: () => <div>select-via-aws</div>,
|
||||
}));
|
||||
|
||||
vi.mock("../../workflow/forms/select-credentials-type/alibabacloud", () => ({
|
||||
SelectViaAlibabaCloud: () => <div>select-via-alibabacloud</div>,
|
||||
}));
|
||||
|
||||
vi.mock("../../workflow/forms/select-credentials-type/cloudflare", () => ({
|
||||
SelectViaCloudflare: () => <div>select-via-cloudflare</div>,
|
||||
}));
|
||||
|
||||
vi.mock("../../workflow/forms/select-credentials-type/gcp", () => ({
|
||||
AddViaServiceAccountForm: () => <div>add-via-service-account-form</div>,
|
||||
SelectViaGCP: () => <div>select-via-gcp</div>,
|
||||
}));
|
||||
|
||||
vi.mock("../../workflow/forms/select-credentials-type/github", () => ({
|
||||
SelectViaGitHub: () => <div>select-via-github</div>,
|
||||
}));
|
||||
|
||||
vi.mock("../../workflow/forms/select-credentials-type/m365", () => ({
|
||||
SelectViaM365: () => <div>select-via-m365</div>,
|
||||
}));
|
||||
|
||||
vi.mock("../../workflow/forms/update-via-service-account-key-form", () => ({
|
||||
UpdateViaServiceAccountForm: () => (
|
||||
<div>update-via-service-account-form</div>
|
||||
),
|
||||
}));
|
||||
|
||||
describe("CredentialsStep", () => {
|
||||
beforeEach(() => {
|
||||
sessionStorage.clear();
|
||||
localStorage.clear();
|
||||
useProviderWizardStore.getState().reset();
|
||||
});
|
||||
|
||||
it("renders update role form when secret already exists in add mode", () => {
|
||||
// Given
|
||||
useProviderWizardStore.setState({
|
||||
providerId: "provider-1",
|
||||
providerType: "aws",
|
||||
providerUid: "111111111111",
|
||||
providerAlias: "Production",
|
||||
via: "role",
|
||||
secretId: "secret-1",
|
||||
mode: PROVIDER_WIZARD_MODE.ADD,
|
||||
});
|
||||
|
||||
// When
|
||||
render(
|
||||
<CredentialsStep
|
||||
onNext={vi.fn()}
|
||||
onBack={vi.fn()}
|
||||
onFooterChange={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
// Then
|
||||
expect(screen.getByText("update-via-role-form")).toBeInTheDocument();
|
||||
expect(screen.queryByText("add-via-role-form")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -4,7 +4,6 @@ import { useEffect, useState } from "react";
|
||||
|
||||
import { getProviderFormType } from "@/lib/provider-helpers";
|
||||
import { useProviderWizardStore } from "@/store/provider-wizard/store";
|
||||
import { PROVIDER_WIZARD_MODE } from "@/types/provider-wizard";
|
||||
import { ProviderType } from "@/types/providers";
|
||||
|
||||
import {
|
||||
@@ -39,7 +38,7 @@ export function CredentialsStep({
|
||||
onBack,
|
||||
onFooterChange,
|
||||
}: CredentialsStepProps) {
|
||||
const { providerId, providerType, providerUid, via, secretId, mode, setVia } =
|
||||
const { providerId, providerType, providerUid, via, secretId, setVia } =
|
||||
useProviderWizardStore();
|
||||
const [isFormLoading, setIsFormLoading] = useState(false);
|
||||
const [isFormValid, setIsFormValid] = useState(false);
|
||||
@@ -50,8 +49,7 @@ export function CredentialsStep({
|
||||
providerType && providerId
|
||||
? getProviderFormType(providerType, via || undefined)
|
||||
: null;
|
||||
const shouldUseUpdateForms =
|
||||
mode === PROVIDER_WIZARD_MODE.UPDATE && Boolean(secretId);
|
||||
const shouldUseUpdateForms = Boolean(secretId);
|
||||
|
||||
const handleBack = () => {
|
||||
if (via) {
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import { render, screen, waitFor } from "@testing-library/react";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { useProviderWizardStore } from "@/store/provider-wizard/store";
|
||||
import { PROVIDER_WIZARD_MODE } from "@/types/provider-wizard";
|
||||
|
||||
import { TestConnectionStep } from "./test-connection-step";
|
||||
|
||||
const { getProviderMock } = vi.hoisted(() => ({
|
||||
getProviderMock: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/actions/providers", () => ({
|
||||
getProvider: getProviderMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../workflow/forms/test-connection-form", () => ({
|
||||
TestConnectionForm: () => <div data-testid="test-connection-form" />,
|
||||
}));
|
||||
|
||||
describe("TestConnectionStep", () => {
|
||||
beforeEach(() => {
|
||||
sessionStorage.clear();
|
||||
localStorage.clear();
|
||||
getProviderMock.mockReset();
|
||||
useProviderWizardStore.getState().reset();
|
||||
});
|
||||
|
||||
it("stores provider secret id after loading provider data", async () => {
|
||||
// Given
|
||||
useProviderWizardStore.setState({
|
||||
providerId: "provider-1",
|
||||
providerType: "aws",
|
||||
mode: PROVIDER_WIZARD_MODE.ADD,
|
||||
});
|
||||
getProviderMock.mockResolvedValue({
|
||||
data: {
|
||||
id: "provider-1",
|
||||
attributes: {
|
||||
uid: "111111111111",
|
||||
provider: "aws",
|
||||
alias: "Production",
|
||||
connection: { connected: false, last_checked_at: null },
|
||||
scanner_args: {},
|
||||
},
|
||||
relationships: {
|
||||
secret: { data: { type: "provider-secrets", id: "secret-1" } },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// When
|
||||
render(
|
||||
<TestConnectionStep
|
||||
onSuccess={vi.fn()}
|
||||
onResetCredentials={vi.fn()}
|
||||
onFooterChange={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
// Then
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId("test-connection-form")).toBeInTheDocument();
|
||||
});
|
||||
expect(useProviderWizardStore.getState().secretId).toBe("secret-1");
|
||||
});
|
||||
});
|
||||
@@ -27,7 +27,8 @@ export function TestConnectionStep({
|
||||
onResetCredentials,
|
||||
onFooterChange,
|
||||
}: TestConnectionStepProps) {
|
||||
const { providerId, providerType, mode } = useProviderWizardStore();
|
||||
const { providerId, providerType, mode, setSecretId } =
|
||||
useProviderWizardStore();
|
||||
const [providerData, setProviderData] =
|
||||
useState<TestConnectionProviderData | null>(null);
|
||||
const [isLoadingProvider, setIsLoadingProvider] = useState(true);
|
||||
@@ -62,11 +63,15 @@ export function TestConnectionStep({
|
||||
setErrorMessage(
|
||||
response.errors[0]?.detail || "Failed to load provider.",
|
||||
);
|
||||
setSecretId(null);
|
||||
setProviderData(null);
|
||||
setIsLoadingProvider(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const resolvedSecretId =
|
||||
response?.data?.relationships?.secret?.data?.id ?? null;
|
||||
setSecretId(resolvedSecretId);
|
||||
setProviderData(response as TestConnectionProviderData);
|
||||
setIsLoadingProvider(false);
|
||||
}
|
||||
@@ -76,7 +81,7 @@ export function TestConnectionStep({
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, [providerId, providerType]);
|
||||
}, [providerId, providerType, setSecretId]);
|
||||
|
||||
useEffect(() => {
|
||||
const canSubmit = !isLoadingProvider && !errorMessage && !!providerData;
|
||||
|
||||
Reference in new issue
Block a user