diff --git a/ui/actions/api-keys/api-keys.ts b/ui/actions/api-keys/api-keys.ts index 2e62932474..4b84041ac5 100644 --- a/ui/actions/api-keys/api-keys.ts +++ b/ui/actions/api-keys/api-keys.ts @@ -9,7 +9,8 @@ import { SingleApiKeyResponse, UpdateApiKeyPayload, } from "@/components/users/profile/api-keys/types"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; import { adaptApiKeysResponse } from "./api-keys.adapter"; diff --git a/ui/actions/attack-paths/queries.test.ts b/ui/actions/attack-paths/queries.test.ts index ab3afc447f..338a82e7c2 100644 --- a/ui/actions/attack-paths/queries.test.ts +++ b/ui/actions/attack-paths/queries.test.ts @@ -13,6 +13,10 @@ vi.mock("@/lib", () => ({ getAuthHeaders: getAuthHeadersMock, })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/server-actions-helper", () => ({ handleApiResponse: handleApiResponseMock, })); diff --git a/ui/actions/attack-paths/queries.ts b/ui/actions/attack-paths/queries.ts index 228c1cca0c..8a6ecce47f 100644 --- a/ui/actions/attack-paths/queries.ts +++ b/ui/actions/attack-paths/queries.ts @@ -2,8 +2,9 @@ import { z } from "zod"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; import { customAttackPathQuerySchema } from "@/lib/attack-paths/custom-query"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiResponse } from "@/lib/server-actions-helper"; import { AttackPathCartographySchema, diff --git a/ui/actions/attack-paths/scans.test.ts b/ui/actions/attack-paths/scans.test.ts index a4ae05bbcf..57a1452b31 100644 --- a/ui/actions/attack-paths/scans.test.ts +++ b/ui/actions/attack-paths/scans.test.ts @@ -19,6 +19,10 @@ vi.mock("@/lib", () => ({ getAuthHeaders: getAuthHeadersMock, })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/server-actions-helper", () => ({ handleApiResponse: handleApiResponseMock, })); diff --git a/ui/actions/attack-paths/scans.ts b/ui/actions/attack-paths/scans.ts index ec3bc927af..68036480e2 100644 --- a/ui/actions/attack-paths/scans.ts +++ b/ui/actions/attack-paths/scans.ts @@ -2,7 +2,8 @@ import { z } from "zod"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiResponse } from "@/lib/server-actions-helper"; import { AttackPathScan, AttackPathScansResponse } from "@/types/attack-paths"; diff --git a/ui/actions/compliances/compliances.ts b/ui/actions/compliances/compliances.ts index e06b06d29d..6ccfbba1e3 100644 --- a/ui/actions/compliances/compliances.ts +++ b/ui/actions/compliances/compliances.ts @@ -1,6 +1,7 @@ "use server"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiResponse } from "@/lib/server-actions-helper"; export const getCompliancesOverview = async ({ diff --git a/ui/actions/finding-groups/finding-groups.test.ts b/ui/actions/finding-groups/finding-groups.test.ts index 00c18e128e..6011dd40f4 100644 --- a/ui/actions/finding-groups/finding-groups.test.ts +++ b/ui/actions/finding-groups/finding-groups.test.ts @@ -39,6 +39,10 @@ vi.mock("@/lib", () => ({ splitCsvFilterValues, })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/provider-filters", () => ({ // Simulate real appendSanitizedProviderFilters: appends all non-undefined filters to the URL. appendSanitizedProviderFilters: vi.fn( diff --git a/ui/actions/finding-groups/finding-groups.ts b/ui/actions/finding-groups/finding-groups.ts index faa697cf32..b740a3b616 100644 --- a/ui/actions/finding-groups/finding-groups.ts +++ b/ui/actions/finding-groups/finding-groups.ts @@ -10,10 +10,10 @@ import { FG_RECENT_LAST_SEEN, FG_SEVERITY_HIGH_FIRST, FINDING_GROUP_RESOURCES_DEFAULT_SORT, - getAuthHeaders, includesMutedFindings, splitCsvFilterValues, } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { appendSanitizedProviderFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; diff --git a/ui/actions/findings/findings-by-resource.test.ts b/ui/actions/findings/findings-by-resource.test.ts index 83406a518f..703da3da02 100644 --- a/ui/actions/findings/findings-by-resource.test.ts +++ b/ui/actions/findings/findings-by-resource.test.ts @@ -35,6 +35,10 @@ vi.mock("@/lib", () => ({ RESOURCE_DRAWER_OTHER_FINDINGS_SORT, })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/provider-filters", () => ({ appendSanitizedProviderTypeFilters: appendSanitizedProviderTypeFiltersMock, })); diff --git a/ui/actions/findings/findings-by-resource.ts b/ui/actions/findings/findings-by-resource.ts index 3d1a6859a0..d9902fa2ec 100644 --- a/ui/actions/findings/findings-by-resource.ts +++ b/ui/actions/findings/findings-by-resource.ts @@ -4,11 +4,8 @@ import { getFindingGroupResources, getLatestFindingGroupResources, } from "@/actions/finding-groups"; -import { - apiBaseUrl, - getAuthHeaders, - RESOURCE_DRAWER_OTHER_FINDINGS_SORT, -} from "@/lib"; +import { apiBaseUrl, RESOURCE_DRAWER_OTHER_FINDINGS_SORT } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { runWithConcurrencyLimit } from "@/lib/concurrency"; import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; diff --git a/ui/actions/findings/findings-triage.test.ts b/ui/actions/findings/findings-triage.test.ts index d494b64be5..15948f1c9c 100644 --- a/ui/actions/findings/findings-triage.test.ts +++ b/ui/actions/findings/findings-triage.test.ts @@ -23,6 +23,10 @@ vi.mock("@/lib", () => ({ getAuthHeaders: getAuthHeadersMock, })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/server-actions-helper", () => ({ handleApiResponse: handleApiResponseMock, })); diff --git a/ui/actions/findings/findings-triage.ts b/ui/actions/findings/findings-triage.ts index c08c7a1335..6291575d21 100644 --- a/ui/actions/findings/findings-triage.ts +++ b/ui/actions/findings/findings-triage.ts @@ -2,7 +2,8 @@ import { adaptLatestFindingTriageNote } from "@/actions/findings/findings-triage.adapter"; import { createMuteRule } from "@/actions/mute-rules"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiResponse } from "@/lib/server-actions-helper"; import { FINDING_TRIAGE_STATUS_LABELS, diff --git a/ui/actions/findings/findings.test.ts b/ui/actions/findings/findings.test.ts index efe04f119c..523e0afeff 100644 --- a/ui/actions/findings/findings.test.ts +++ b/ui/actions/findings/findings.test.ts @@ -23,6 +23,10 @@ vi.mock("@/lib", () => ({ getAuthHeaders: getAuthHeadersMock, })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/provider-filters", () => ({ appendSanitizedProviderTypeFilters: appendSanitizedProviderTypeFiltersMock, })); diff --git a/ui/actions/findings/findings.ts b/ui/actions/findings/findings.ts index 0635d273ce..11073b4f2f 100644 --- a/ui/actions/findings/findings.ts +++ b/ui/actions/findings/findings.ts @@ -4,7 +4,8 @@ import { redirect } from "next/navigation"; import { attachFindingTriageSummariesToResponse } from "@/actions/findings/findings-triage.adapter"; import { getFindingTriageAdapterOptions } from "@/actions/findings/findings-triage.options"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; diff --git a/ui/actions/integrations/integrations.ts b/ui/actions/integrations/integrations.ts index 8945842fe4..c1af591316 100644 --- a/ui/actions/integrations/integrations.ts +++ b/ui/actions/integrations/integrations.ts @@ -3,7 +3,8 @@ import { revalidatePath } from "next/cache"; import { pollTaskUntilSettled } from "@/actions/task/poll"; -import { apiBaseUrl, getAuthHeaders, parseStringify } from "@/lib"; +import { apiBaseUrl, parseStringify } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; import { IntegrationType } from "@/types/integrations"; import type { TaskState } from "@/types/tasks"; diff --git a/ui/actions/integrations/jira-dispatch.test.ts b/ui/actions/integrations/jira-dispatch.test.ts index 05c3188e47..d5042bb09d 100644 --- a/ui/actions/integrations/jira-dispatch.test.ts +++ b/ui/actions/integrations/jira-dispatch.test.ts @@ -13,6 +13,10 @@ vi.mock("@/lib", () => ({ getAuthHeaders: vi.fn(), })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: vi.fn(), +})); + vi.mock("@/lib/server-actions-helper", () => ({ handleApiError: vi.fn(), })); diff --git a/ui/actions/integrations/jira-dispatch.ts b/ui/actions/integrations/jira-dispatch.ts index b6d3215e13..4ffbce85f0 100644 --- a/ui/actions/integrations/jira-dispatch.ts +++ b/ui/actions/integrations/jira-dispatch.ts @@ -1,7 +1,8 @@ "use server"; import { pollTaskUntilSettled } from "@/actions/task/poll"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiError } from "@/lib/server-actions-helper"; import type { IntegrationProps, diff --git a/ui/actions/integrations/saml.ts b/ui/actions/integrations/saml.ts index 41e153a46a..294e9b37d0 100644 --- a/ui/actions/integrations/saml.ts +++ b/ui/actions/integrations/saml.ts @@ -2,7 +2,8 @@ import { revalidatePath } from "next/cache"; -import { apiBaseUrl, getAuthHeaders } from "@/lib/helper"; +import { getAuthHeaders } from "@/lib/auth-headers"; +import { apiBaseUrl } from "@/lib/helper"; import { handleApiResponse } from "@/lib/server-actions-helper"; import { samlConfigFormSchema } from "@/types/formSchemas"; diff --git a/ui/actions/invitations/invitation.ts b/ui/actions/invitations/invitation.ts index 72f591705a..a1eb76eeba 100644 --- a/ui/actions/invitations/invitation.ts +++ b/ui/actions/invitations/invitation.ts @@ -4,7 +4,8 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { z } from "zod"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; const invitationTokenSchema = z.string().min(1).max(500); diff --git a/ui/actions/lighthouse-v1/lighthouse.ts b/ui/actions/lighthouse-v1/lighthouse.ts index 635571f69e..8da3630c8a 100644 --- a/ui/actions/lighthouse-v1/lighthouse.ts +++ b/ui/actions/lighthouse-v1/lighthouse.ts @@ -1,6 +1,7 @@ "use server"; -import { apiBaseUrl, getAuthHeaders } from "@/lib/helper"; +import { getAuthHeaders } from "@/lib/auth-headers"; +import { apiBaseUrl } from "@/lib/helper"; import { validateBaseUrl, validateCredentials, diff --git a/ui/actions/manage-groups/manage-groups.test.ts b/ui/actions/manage-groups/manage-groups.test.ts index c016832a1f..8e79a0f0ed 100644 --- a/ui/actions/manage-groups/manage-groups.test.ts +++ b/ui/actions/manage-groups/manage-groups.test.ts @@ -26,6 +26,10 @@ vi.mock("@/lib", () => ({ getErrorMessage: vi.fn(), })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/server-actions-helper", () => ({ handleApiError: handleApiErrorMock, handleApiResponse: handleApiResponseMock, @@ -111,6 +115,16 @@ describe("getAllProviderGroups", () => { expect(result).toBeUndefined(); }); + it("rethrows the framework redirect from authentication", async () => { + // Given + const redirectError = new Error("NEXT_REDIRECT"); + getAuthHeadersMock.mockRejectedValueOnce(redirectError); + + // When / Then + await expect(getAllProviderGroups()).rejects.toBe(redirectError); + expect(fetchMock).not.toHaveBeenCalled(); + }); + it("returns undefined when a later page resolves to an error payload", async () => { handleApiResponseMock .mockResolvedValueOnce(makePage([makeGroup("g1", "Group 1")], 1, 2)) diff --git a/ui/actions/manage-groups/manage-groups.ts b/ui/actions/manage-groups/manage-groups.ts index c916a89d39..cfb52a62b3 100644 --- a/ui/actions/manage-groups/manage-groups.ts +++ b/ui/actions/manage-groups/manage-groups.ts @@ -3,7 +3,8 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; -import { apiBaseUrl, getAuthHeaders, getErrorMessage } from "@/lib"; +import { apiBaseUrl, getErrorMessage } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; import { ManageGroupPayload, ProviderGroupsResponse } from "@/types/components"; @@ -65,9 +66,9 @@ export const getAllProviderGroups = async (): Promise< const allGroups: ProviderGroupsResponse["data"] = []; let lastResponse: ProviderGroupsResponse | undefined; let hasMorePages = true; + const headers = await getAuthHeaders({ contentType: false }); try { - const headers = await getAuthHeaders({ contentType: false }); while (hasMorePages && currentPage <= maxPages) { const url = new URL(`${apiBaseUrl}/provider-groups`); url.searchParams.append("page[number]", currentPage.toString()); diff --git a/ui/actions/mute-rules/mute-rules.ts b/ui/actions/mute-rules/mute-rules.ts index c74c4a7e2a..c0e48f65fd 100644 --- a/ui/actions/mute-rules/mute-rules.ts +++ b/ui/actions/mute-rules/mute-rules.ts @@ -2,7 +2,8 @@ import { revalidatePath } from "next/cache"; -import { apiBaseUrl, getAuthHeaders } from "@/lib/helper"; +import { getAuthHeaders } from "@/lib/auth-headers"; +import { apiBaseUrl } from "@/lib/helper"; import { DeleteMuteRuleActionState, diff --git a/ui/actions/organizations/organizations.test.ts b/ui/actions/organizations/organizations.test.ts index be1eb6c404..ff540d243c 100644 --- a/ui/actions/organizations/organizations.test.ts +++ b/ui/actions/organizations/organizations.test.ts @@ -23,6 +23,10 @@ vi.mock("@/lib", () => ({ getAuthHeaders: getAuthHeadersMock, })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/server-actions-helper", () => ({ handleApiError: handleApiErrorMock, handleApiResponse: handleApiResponseMock, diff --git a/ui/actions/organizations/organizations.ts b/ui/actions/organizations/organizations.ts index 9c3caf1080..d5c9c8690a 100644 --- a/ui/actions/organizations/organizations.ts +++ b/ui/actions/organizations/organizations.ts @@ -2,7 +2,8 @@ import { revalidatePath } from "next/cache"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; import { OrganizationListResponse, diff --git a/ui/actions/overview/attack-surface/attack-surface.ts b/ui/actions/overview/attack-surface/attack-surface.ts index 4a97a406d4..192b4b19a0 100644 --- a/ui/actions/overview/attack-surface/attack-surface.ts +++ b/ui/actions/overview/attack-surface/attack-surface.ts @@ -1,6 +1,7 @@ "use server"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; diff --git a/ui/actions/overview/compliance-watchlist/compliance-watchlist.ts b/ui/actions/overview/compliance-watchlist/compliance-watchlist.ts index 026a1b426b..462d848a04 100644 --- a/ui/actions/overview/compliance-watchlist/compliance-watchlist.ts +++ b/ui/actions/overview/compliance-watchlist/compliance-watchlist.ts @@ -1,6 +1,7 @@ "use server"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; diff --git a/ui/actions/overview/findings/findings.ts b/ui/actions/overview/findings/findings.ts index 2aa771fb26..0098b5bbf2 100644 --- a/ui/actions/overview/findings/findings.ts +++ b/ui/actions/overview/findings/findings.ts @@ -2,7 +2,8 @@ import { redirect } from "next/navigation"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; diff --git a/ui/actions/overview/providers/providers.ts b/ui/actions/overview/providers/providers.ts index 9aaec5df8c..eaa02508d6 100644 --- a/ui/actions/overview/providers/providers.ts +++ b/ui/actions/overview/providers/providers.ts @@ -2,7 +2,8 @@ import { redirect } from "next/navigation"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; diff --git a/ui/actions/overview/regions/regions.ts b/ui/actions/overview/regions/regions.ts index 31610892ef..9a005a9273 100644 --- a/ui/actions/overview/regions/regions.ts +++ b/ui/actions/overview/regions/regions.ts @@ -1,6 +1,7 @@ "use server"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; diff --git a/ui/actions/overview/resources-inventory/resources-inventory.ts b/ui/actions/overview/resources-inventory/resources-inventory.ts index 264da6e375..1c35342b88 100644 --- a/ui/actions/overview/resources-inventory/resources-inventory.ts +++ b/ui/actions/overview/resources-inventory/resources-inventory.ts @@ -1,6 +1,7 @@ "use server"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; diff --git a/ui/actions/overview/risk-radar/risk-radar.ts b/ui/actions/overview/risk-radar/risk-radar.ts index 419330dc18..fad795a8b3 100644 --- a/ui/actions/overview/risk-radar/risk-radar.ts +++ b/ui/actions/overview/risk-radar/risk-radar.ts @@ -1,6 +1,7 @@ "use server"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; diff --git a/ui/actions/overview/services/services.ts b/ui/actions/overview/services/services.ts index 1e55c04531..10fa4dcb8c 100644 --- a/ui/actions/overview/services/services.ts +++ b/ui/actions/overview/services/services.ts @@ -1,6 +1,7 @@ "use server"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; diff --git a/ui/actions/overview/severity-trends/severity-trends.ts b/ui/actions/overview/severity-trends/severity-trends.ts index e90efa15b7..51223e3346 100644 --- a/ui/actions/overview/severity-trends/severity-trends.ts +++ b/ui/actions/overview/severity-trends/severity-trends.ts @@ -4,7 +4,8 @@ import { getDateFromForTimeRange, type TimeRange, } from "@/app/(prowler)/_overview/severity-over-time/_constants/time-range.constants"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; diff --git a/ui/actions/overview/threat-score/threat-score.ts b/ui/actions/overview/threat-score/threat-score.ts index 0a1d7505d1..7dee7e4105 100644 --- a/ui/actions/overview/threat-score/threat-score.ts +++ b/ui/actions/overview/threat-score/threat-score.ts @@ -1,6 +1,7 @@ "use server"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; diff --git a/ui/actions/processors/processors.ts b/ui/actions/processors/processors.ts index f177dc9ac4..3b270a436b 100644 --- a/ui/actions/processors/processors.ts +++ b/ui/actions/processors/processors.ts @@ -1,6 +1,7 @@ "use server"; -import { apiBaseUrl, getAuthHeaders } from "@/lib/helper"; +import { getAuthHeaders } from "@/lib/auth-headers"; +import { apiBaseUrl } from "@/lib/helper"; import { mutedFindingsConfigFormSchema } from "@/types/formSchemas"; import { DeleteMutedFindingsConfigActionState, diff --git a/ui/actions/providers/providers.test.ts b/ui/actions/providers/providers.test.ts index 4d56e45b4b..8a598f7297 100644 --- a/ui/actions/providers/providers.test.ts +++ b/ui/actions/providers/providers.test.ts @@ -29,6 +29,10 @@ vi.mock("@/lib", () => ({ wait: vi.fn(), })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/provider-credentials/build-credentials", () => ({ buildSecretConfig: vi.fn(() => ({ secretType: "access-secret-key", diff --git a/ui/actions/providers/providers.ts b/ui/actions/providers/providers.ts index 010646dc34..c78d933697 100644 --- a/ui/actions/providers/providers.ts +++ b/ui/actions/providers/providers.ts @@ -3,7 +3,8 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; -import { apiBaseUrl, getAuthHeaders, getFormValue, wait } from "@/lib"; +import { apiBaseUrl, getFormValue, wait } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { buildSecretConfig } from "@/lib/provider-credentials/build-credentials"; import { ProviderCredentialFields } from "@/lib/provider-credentials/provider-credential-fields"; import { appendSanitizedProviderInFilters } from "@/lib/provider-filters"; diff --git a/ui/actions/resources/resources.test.ts b/ui/actions/resources/resources.test.ts index 5f45b7815a..9dc59345f1 100644 --- a/ui/actions/resources/resources.test.ts +++ b/ui/actions/resources/resources.test.ts @@ -43,6 +43,10 @@ vi.mock("@/lib", () => ({ splitCsvFilterValues, })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/server-actions-helper", () => ({ handleApiResponse: handleApiResponseMock, })); diff --git a/ui/actions/resources/resources.ts b/ui/actions/resources/resources.ts index 3ab84efa4f..e220ceb616 100644 --- a/ui/actions/resources/resources.ts +++ b/ui/actions/resources/resources.ts @@ -8,9 +8,9 @@ import { apiBaseUrl, FINDINGS_FILTERED_SORT, GENERIC_SERVER_ERROR_MESSAGE, - getAuthHeaders, sanitizeErrorMessage, } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; import { OrganizationResource } from "@/types/organizations"; diff --git a/ui/actions/roles/roles.test.ts b/ui/actions/roles/roles.test.ts index 1e5dfaf189..850dae31d9 100644 --- a/ui/actions/roles/roles.test.ts +++ b/ui/actions/roles/roles.test.ts @@ -25,6 +25,10 @@ vi.mock("@/lib", () => ({ getAuthHeaders: getAuthHeadersMock, })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/server-actions-helper", () => ({ handleApiError: handleApiErrorMock, handleApiResponse: handleApiResponseMock, diff --git a/ui/actions/roles/roles.ts b/ui/actions/roles/roles.ts index 645db72951..c778fe1a16 100644 --- a/ui/actions/roles/roles.ts +++ b/ui/actions/roles/roles.ts @@ -3,7 +3,8 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; export const getRoles = async ({ diff --git a/ui/actions/scan-configurations/scan-configurations.ts b/ui/actions/scan-configurations/scan-configurations.ts index 946fdeca82..b7cc885054 100644 --- a/ui/actions/scan-configurations/scan-configurations.ts +++ b/ui/actions/scan-configurations/scan-configurations.ts @@ -4,7 +4,8 @@ import yaml from "js-yaml"; import { revalidatePath } from "next/cache"; import { z } from "zod"; -import { apiBaseUrl, getAuthHeaders } from "@/lib/helper"; +import { getAuthHeaders } from "@/lib/auth-headers"; +import { apiBaseUrl } from "@/lib/helper"; import { scanConfigurationFormSchema } from "@/types/formSchemas"; import { DeleteScanConfigurationActionState, diff --git a/ui/actions/scans/scans.test.ts b/ui/actions/scans/scans.test.ts index a7f7fd0c7e..b5ecdab95d 100644 --- a/ui/actions/scans/scans.test.ts +++ b/ui/actions/scans/scans.test.ts @@ -21,6 +21,10 @@ vi.mock("@/lib", () => ({ error instanceof Error ? error.message : String(error), })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/server-actions-helper", () => ({ handleApiError: handleApiErrorMock, handleApiResponse: handleApiResponseMock, diff --git a/ui/actions/scans/scans.ts b/ui/actions/scans/scans.ts index e192bb5b49..ccee122a48 100644 --- a/ui/actions/scans/scans.ts +++ b/ui/actions/scans/scans.ts @@ -6,9 +6,9 @@ import { redirect } from "next/navigation"; import { apiBaseUrl, GENERIC_SERVER_ERROR_MESSAGE, - getAuthHeaders, getErrorMessage, } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { COMPLIANCE_REPORT_DISPLAY_NAMES, type ComplianceReportType, diff --git a/ui/actions/schedules/schedules.test.ts b/ui/actions/schedules/schedules.test.ts index 3122430f83..16fa97ea74 100644 --- a/ui/actions/schedules/schedules.test.ts +++ b/ui/actions/schedules/schedules.test.ts @@ -28,6 +28,10 @@ vi.mock("@/lib", () => ({ getAuthHeaders: getAuthHeadersMock, })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/server-actions-helper", () => ({ handleApiError: handleApiErrorMock, handleApiResponse: handleApiResponseMock, diff --git a/ui/actions/schedules/schedules.ts b/ui/actions/schedules/schedules.ts index 63ef862b3c..2d87a1b679 100644 --- a/ui/actions/schedules/schedules.ts +++ b/ui/actions/schedules/schedules.ts @@ -3,7 +3,8 @@ import { revalidatePath } from "next/cache"; import { z } from "zod"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { scheduleUpdatePayloadSchema } from "@/lib/schedules"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; import type { diff --git a/ui/actions/task/tasks.ts b/ui/actions/task/tasks.ts index bfe7d907b5..ca18b85f02 100644 --- a/ui/actions/task/tasks.ts +++ b/ui/actions/task/tasks.ts @@ -1,6 +1,7 @@ "use server"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; export const getTask = async (taskId: string) => { diff --git a/ui/actions/users/tenants.ts b/ui/actions/users/tenants.ts index 79723debaa..ac50a1fce4 100644 --- a/ui/actions/users/tenants.ts +++ b/ui/actions/users/tenants.ts @@ -4,7 +4,8 @@ import { revalidatePath } from "next/cache"; import { z } from "zod"; import { signOut } from "@/auth.config"; -import { apiBaseUrl, getAuthHeaders } from "@/lib/helper"; +import { getAuthHeaders } from "@/lib/auth-headers"; +import { apiBaseUrl } from "@/lib/helper"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; export const getAllTenants = async () => { diff --git a/ui/actions/users/users.ts b/ui/actions/users/users.ts index 446fa81812..039fabae11 100644 --- a/ui/actions/users/users.ts +++ b/ui/actions/users/users.ts @@ -5,7 +5,8 @@ import { redirect } from "next/navigation"; import { z } from "zod"; import { auth } from "@/auth.config"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; import { TENANT_MEMBERSHIP_ROLE, diff --git a/ui/app/(prowler)/alerts/_actions/alerts.test.ts b/ui/app/(prowler)/alerts/_actions/alerts.test.ts index 5f19b33733..71c87716f1 100644 --- a/ui/app/(prowler)/alerts/_actions/alerts.test.ts +++ b/ui/app/(prowler)/alerts/_actions/alerts.test.ts @@ -19,6 +19,10 @@ vi.mock("@/lib", () => ({ error instanceof Error ? error.message : String(error), })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/server-actions-helper", () => ({ handleApiError: handleApiErrorMock, handleApiResponse: handleApiResponseMock, diff --git a/ui/app/(prowler)/alerts/_actions/alerts.ts b/ui/app/(prowler)/alerts/_actions/alerts.ts index a260636c0b..f84e0edf65 100644 --- a/ui/app/(prowler)/alerts/_actions/alerts.ts +++ b/ui/app/(prowler)/alerts/_actions/alerts.ts @@ -1,6 +1,7 @@ "use server"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; import { diff --git a/ui/app/(prowler)/alerts/_actions/recipients.test.ts b/ui/app/(prowler)/alerts/_actions/recipients.test.ts index 1a51a0d34a..78145b0b05 100644 --- a/ui/app/(prowler)/alerts/_actions/recipients.test.ts +++ b/ui/app/(prowler)/alerts/_actions/recipients.test.ts @@ -19,6 +19,10 @@ vi.mock("@/lib", () => ({ error instanceof Error ? error.message : String(error), })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/server-actions-helper", () => ({ handleApiError: handleApiErrorMock, handleApiResponse: handleApiResponseMock, diff --git a/ui/app/(prowler)/alerts/_actions/recipients.ts b/ui/app/(prowler)/alerts/_actions/recipients.ts index 8d528b19f7..ba440b64a8 100644 --- a/ui/app/(prowler)/alerts/_actions/recipients.ts +++ b/ui/app/(prowler)/alerts/_actions/recipients.ts @@ -1,6 +1,7 @@ "use server"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; const RECIPIENTS_PATH = "/alerts/recipients"; diff --git a/ui/app/(prowler)/compliance/_actions/cross-provider.test.ts b/ui/app/(prowler)/compliance/_actions/cross-provider.test.ts index edd1481aac..33d4fd349c 100644 --- a/ui/app/(prowler)/compliance/_actions/cross-provider.test.ts +++ b/ui/app/(prowler)/compliance/_actions/cross-provider.test.ts @@ -20,6 +20,10 @@ vi.mock("@/lib", () => ({ GENERIC_SERVER_ERROR_MESSAGE: "Generic server error.", })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + vi.mock("@/lib/server-actions-helper", () => ({ handleApiResponse: handleApiResponseMock, })); diff --git a/ui/app/(prowler)/compliance/_actions/cross-provider.ts b/ui/app/(prowler)/compliance/_actions/cross-provider.ts index eacdc29fde..90a81a9580 100644 --- a/ui/app/(prowler)/compliance/_actions/cross-provider.ts +++ b/ui/app/(prowler)/compliance/_actions/cross-provider.ts @@ -6,10 +6,10 @@ import type { ScanBinaryResult } from "@/actions/scans/scans"; import { apiBaseUrl, GENERIC_SERVER_ERROR_MESSAGE, - getAuthHeaders, getErrorMessage, } from "@/lib"; import { hasActionError } from "@/lib/action-errors"; +import { getAuthHeaders } from "@/lib/auth-headers"; import { handleApiResponse } from "@/lib/server-actions-helper"; import { SentryErrorSource, SentryErrorType } from "@/sentry"; diff --git a/ui/app/(prowler)/lighthouse/_actions/lighthouse-v2.test.ts b/ui/app/(prowler)/lighthouse/_actions/lighthouse-v2.test.ts index bab81d7157..b7ed404411 100644 --- a/ui/app/(prowler)/lighthouse/_actions/lighthouse-v2.test.ts +++ b/ui/app/(prowler)/lighthouse/_actions/lighthouse-v2.test.ts @@ -24,6 +24,12 @@ vi.mock("@/lib/helper", () => ({ GENERIC_SERVER_ERROR_MESSAGE: "Server error", })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: vi + .fn() + .mockResolvedValue({ Authorization: "Bearer token-123" }), +})); + import { createLighthouseV2Session, getLighthouseV2SupportedModels, diff --git a/ui/app/(prowler)/lighthouse/_actions/lighthouse-v2.ts b/ui/app/(prowler)/lighthouse/_actions/lighthouse-v2.ts index c78233b35f..720b403bde 100644 --- a/ui/app/(prowler)/lighthouse/_actions/lighthouse-v2.ts +++ b/ui/app/(prowler)/lighthouse/_actions/lighthouse-v2.ts @@ -13,7 +13,8 @@ import type { LighthouseV2SupportedModel, LighthouseV2SupportedProvider, } from "@/app/(prowler)/lighthouse/_types"; -import { apiBaseUrl, getAuthHeaders } from "@/lib/helper"; +import { getAuthHeaders } from "@/lib/auth-headers"; +import { apiBaseUrl } from "@/lib/helper"; import { LIGHTHOUSE_ROUTE } from "@/lib/lighthouse-routes"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; import type { JsonApiDocument } from "@/types/jsonapi"; diff --git a/ui/app/api/scans/[scanId]/report/route.test.ts b/ui/app/api/scans/[scanId]/report/route.test.ts index ad5e9194ea..92856e2daa 100644 --- a/ui/app/api/scans/[scanId]/report/route.test.ts +++ b/ui/app/api/scans/[scanId]/report/route.test.ts @@ -11,6 +11,10 @@ vi.mock("@/lib", () => ({ getAuthHeaders: getAuthHeadersMock, })); +vi.mock("@/lib/auth-headers", () => ({ + getAuthHeaders: getAuthHeadersMock, +})); + describe("GET /api/scans/[scanId]/report", () => { afterEach(() => { vi.unstubAllGlobals(); diff --git a/ui/app/api/scans/[scanId]/report/route.ts b/ui/app/api/scans/[scanId]/report/route.ts index 5b891385cb..3707f14e04 100644 --- a/ui/app/api/scans/[scanId]/report/route.ts +++ b/ui/app/api/scans/[scanId]/report/route.ts @@ -1,6 +1,7 @@ import { NextResponse } from "next/server"; -import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { apiBaseUrl } from "@/lib"; +import { getAuthHeaders } from "@/lib/auth-headers"; export const dynamic = "force-dynamic"; export const runtime = "nodejs"; diff --git a/ui/lib/auth-headers.test.ts b/ui/lib/auth-headers.test.ts new file mode 100644 index 0000000000..6488eeb2ff --- /dev/null +++ b/ui/lib/auth-headers.test.ts @@ -0,0 +1,43 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const { authMock, getRequiredAuthHeadersMock } = vi.hoisted(() => ({ + authMock: vi.fn(), + getRequiredAuthHeadersMock: vi.fn(), +})); + +vi.mock("server-only", () => ({})); + +vi.mock("@/auth.config", () => ({ + auth: authMock, +})); + +vi.mock("./server-auth", () => ({ + getRequiredAuthHeaders: getRequiredAuthHeadersMock, +})); + +import { getAuthHeaders } from "./auth-headers"; + +describe("getAuthHeaders", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("forwards the restored session and requested header options", async () => { + // Given + authMock.mockResolvedValue({ + accessToken: "access-token", + error: "RefreshAccessTokenError", + }); + const options = { contentType: true }; + + // When + await getAuthHeaders(options); + + // Then + expect(getRequiredAuthHeadersMock).toHaveBeenCalledWith( + "access-token", + options, + "RefreshAccessTokenError", + ); + }); +}); diff --git a/ui/lib/auth-headers.ts b/ui/lib/auth-headers.ts new file mode 100644 index 0000000000..e497df26bf --- /dev/null +++ b/ui/lib/auth-headers.ts @@ -0,0 +1,11 @@ +import "server-only"; + +import { auth } from "@/auth.config"; + +import { getRequiredAuthHeaders } from "./server-auth"; + +export const getAuthHeaders = async (options?: { contentType?: boolean }) => { + const session = await auth(); + + return getRequiredAuthHeaders(session?.accessToken, options, session?.error); +}; diff --git a/ui/lib/helper.test.ts b/ui/lib/helper.test.ts index f59dda487b..25ec0ae6e5 100644 --- a/ui/lib/helper.test.ts +++ b/ui/lib/helper.test.ts @@ -15,10 +15,6 @@ vi.mock("@/actions/task", () => ({ getTask: vi.fn(), })); -vi.mock("@/auth.config", () => ({ - auth: vi.fn(), -})); - const createToast = () => vi.fn(); const getAnchor = () => { diff --git a/ui/lib/helper.ts b/ui/lib/helper.ts index c7c714aca8..fe4c1d625c 100644 --- a/ui/lib/helper.ts +++ b/ui/lib/helper.ts @@ -5,7 +5,6 @@ import { type ScanBinaryResult, } from "@/actions/scans"; import { getTask } from "@/actions/task"; -import { auth } from "@/auth.config"; import { useToast } from "@/components/shadcn"; import { COMPLIANCE_REPORT_DISPLAY_NAMES, @@ -14,8 +13,6 @@ import { import { readEnv } from "@/lib/runtime-env"; import { AuthSocialProvider, MetaDataProps, PermissionInfo } from "@/types"; -import { getRequiredAuthHeaders } from "./server-auth"; - export const baseUrl = process.env.AUTH_URL; export const apiBaseUrl = readEnv( "UI_API_BASE_URL", @@ -55,17 +52,6 @@ export function filterEmptyValues( ); } -/** - * Returns the authentication headers for API requests - * @param options - Optional configuration options - * @returns Authentication headers with Accept and Authorization - */ -export const getAuthHeaders = async (options?: { contentType?: boolean }) => { - const session = await auth(); - - return getRequiredAuthHeaders(session?.accessToken, options, session?.error); -}; - export const getAuthUrl = (provider: AuthSocialProvider) => { const config = { google: { diff --git a/ui/lib/server-auth.test.ts b/ui/lib/server-auth.test.ts index 9d22cd1efb..8d1815787d 100644 --- a/ui/lib/server-auth.test.ts +++ b/ui/lib/server-auth.test.ts @@ -7,6 +7,8 @@ const { headersMock, redirectMock } = vi.hoisted(() => ({ }), })); +vi.mock("server-only", () => ({})); + vi.mock("next/headers", () => ({ headers: headersMock, })); diff --git a/ui/lib/server-auth.ts b/ui/lib/server-auth.ts index b292a11233..e63b922613 100644 --- a/ui/lib/server-auth.ts +++ b/ui/lib/server-auth.ts @@ -1,3 +1,5 @@ +import "server-only"; + import { headers } from "next/headers"; import { redirect } from "next/navigation"; diff --git a/ui/vitest.browser.setup.ts b/ui/vitest.browser.setup.ts index 199b0d474f..dddedd90a4 100644 --- a/ui/vitest.browser.setup.ts +++ b/ui/vitest.browser.setup.ts @@ -10,6 +10,8 @@ import { afterAll, afterEach, beforeAll, vi } from "vitest"; import { worker } from "./__tests__/msw/worker"; +vi.mock("server-only", () => ({})); + // Server Actions ("use server") are bundled by Vite as plain async functions // — the directive is a Next.js compiler concept, not part of Vite. When the // page invokes one, it runs in the browser and reaches `auth()` from