mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-05 03:12:14 +00:00
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
178 lines
5.6 KiB
TypeScript
178 lines
5.6 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const { fetchCurrentUserMock } = vi.hoisted(() => ({
|
|
fetchCurrentUserMock: vi.fn(),
|
|
}));
|
|
vi.mock("server-only", () => ({}));
|
|
vi.mock("@/lib/auth/current-user", () => ({
|
|
fetchCurrentUser: fetchCurrentUserMock,
|
|
}));
|
|
|
|
import { REGISTRY_ACCESS } from "./access";
|
|
import {
|
|
evaluateRegistryAccess,
|
|
evaluateRegistryProviderAccess,
|
|
} from "./access.server";
|
|
|
|
describe("Registry provider onboarding access", () => {
|
|
beforeEach(() => {
|
|
vi.stubEnv("UI_CLOUD_ENABLED", "true");
|
|
vi.stubEnv("UI_REGISTRY_ENABLED", "true");
|
|
});
|
|
|
|
it.each([false, undefined])(
|
|
"allows provider managers without Registry permission (%s)",
|
|
async (manageRegistry) => {
|
|
// Given
|
|
fetchCurrentUserMock.mockResolvedValue({
|
|
manageRegistry,
|
|
permissions: { manage_providers: true },
|
|
});
|
|
// When / Then
|
|
await expect(
|
|
evaluateRegistryProviderAccess("access-token"),
|
|
).resolves.toEqual({
|
|
status: REGISTRY_ACCESS.ELIGIBLE,
|
|
});
|
|
await expect(evaluateRegistryAccess("access-token")).resolves.not.toEqual(
|
|
{
|
|
status: REGISTRY_ACCESS.ELIGIBLE,
|
|
},
|
|
);
|
|
},
|
|
);
|
|
|
|
it("denies onboarding to a Registry manager without manage_providers", async () => {
|
|
// Given
|
|
fetchCurrentUserMock.mockResolvedValue({
|
|
manageRegistry: true,
|
|
permissions: { manage_providers: false },
|
|
});
|
|
// When / Then
|
|
await expect(
|
|
evaluateRegistryProviderAccess("access-token"),
|
|
).resolves.toEqual({
|
|
status: REGISTRY_ACCESS.INELIGIBLE,
|
|
});
|
|
await expect(evaluateRegistryAccess("access-token")).resolves.toEqual({
|
|
status: REGISTRY_ACCESS.ELIGIBLE,
|
|
});
|
|
});
|
|
|
|
it.each([
|
|
["false", "true", "access-token"],
|
|
["true", "false", "access-token"],
|
|
["true", "true", ""],
|
|
])(
|
|
"requires enabled flags and a token: %j / %j / %j",
|
|
async (cloud, flag, token) => {
|
|
// Given
|
|
vi.stubEnv("UI_CLOUD_ENABLED", cloud);
|
|
vi.stubEnv("UI_REGISTRY_ENABLED", flag);
|
|
// When / Then
|
|
await expect(evaluateRegistryProviderAccess(token)).resolves.toEqual({
|
|
status: REGISTRY_ACCESS.INELIGIBLE,
|
|
});
|
|
expect(fetchCurrentUserMock).not.toHaveBeenCalled();
|
|
},
|
|
);
|
|
|
|
it("checks current provider permission again after revocation", async () => {
|
|
// Given
|
|
fetchCurrentUserMock
|
|
.mockResolvedValueOnce({ permissions: { manage_providers: true } })
|
|
.mockResolvedValueOnce({ permissions: { manage_providers: false } });
|
|
// When / Then
|
|
await expect(
|
|
evaluateRegistryProviderAccess("access-token"),
|
|
).resolves.toEqual({
|
|
status: REGISTRY_ACCESS.ELIGIBLE,
|
|
});
|
|
await expect(
|
|
evaluateRegistryProviderAccess("access-token"),
|
|
).resolves.toEqual({
|
|
status: REGISTRY_ACCESS.INELIGIBLE,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("evaluateRegistryAccess", () => {
|
|
beforeEach(() => {
|
|
vi.stubEnv("UI_CLOUD_ENABLED", "true");
|
|
vi.stubEnv("UI_REGISTRY_ENABLED", "true");
|
|
fetchCurrentUserMock.mockResolvedValue({ manageRegistry: true });
|
|
});
|
|
|
|
it("allows a fresh exact-true current permission without lease metadata", async () => {
|
|
// Given / When
|
|
const result = await evaluateRegistryAccess("access-token");
|
|
// Then
|
|
expect(result).toStrictEqual({ status: REGISTRY_ACCESS.ELIGIBLE });
|
|
});
|
|
|
|
it.each([
|
|
[undefined, "true", "access-token", true, REGISTRY_ACCESS.INELIGIBLE, 0],
|
|
["true", "false", "access-token", true, REGISTRY_ACCESS.INELIGIBLE, 0],
|
|
["true", "true", "access-token", false, REGISTRY_ACCESS.INELIGIBLE, 1],
|
|
["true", "true", "access-token", undefined, REGISTRY_ACCESS.UNKNOWN, 1],
|
|
["true", "true", "", true, REGISTRY_ACCESS.INELIGIBLE, 0],
|
|
])(
|
|
"fails closed without trusting stale JWT authority",
|
|
async (cloud, flag, token, permission, expected, calls) => {
|
|
// Given
|
|
vi.stubEnv("UI_CLOUD_ENABLED", cloud);
|
|
vi.stubEnv("UI_REGISTRY_ENABLED", flag);
|
|
fetchCurrentUserMock.mockResolvedValue({ manageRegistry: permission });
|
|
// When / Then
|
|
await expect(evaluateRegistryAccess(token)).resolves.toMatchObject({
|
|
status: expected,
|
|
});
|
|
expect(fetchCurrentUserMock).toHaveBeenCalledTimes(calls);
|
|
},
|
|
);
|
|
|
|
it.each([
|
|
[" true ", "true"],
|
|
["true", " true "],
|
|
["\ttrue\n", "\ttrue\n"],
|
|
])(
|
|
"accepts whitespace around enabled flags: %j / %j",
|
|
async (cloud, flag) => {
|
|
// Given
|
|
vi.stubEnv("UI_CLOUD_ENABLED", cloud);
|
|
vi.stubEnv("UI_REGISTRY_ENABLED", flag);
|
|
// When / Then
|
|
await expect(evaluateRegistryAccess("access-token")).resolves.toEqual({
|
|
status: REGISTRY_ACCESS.ELIGIBLE,
|
|
});
|
|
},
|
|
);
|
|
|
|
it("returns unknown for malformed, network, abort, and timeout evidence", async () => {
|
|
// Given
|
|
fetchCurrentUserMock
|
|
.mockResolvedValueOnce({ manageRegistry: undefined })
|
|
.mockRejectedValueOnce(new Error("network"))
|
|
.mockRejectedValueOnce(new DOMException("aborted", "AbortError"))
|
|
.mockImplementationOnce(
|
|
(_token, { signal }) =>
|
|
new Promise((_, reject) => signal.addEventListener("abort", reject)),
|
|
);
|
|
// When / Then
|
|
const expectUnknown = () =>
|
|
expect(evaluateRegistryAccess("access-token")).resolves.toMatchObject({
|
|
status: REGISTRY_ACCESS.UNKNOWN,
|
|
});
|
|
await expectUnknown();
|
|
await expectUnknown();
|
|
await expectUnknown();
|
|
vi.useFakeTimers();
|
|
const result = evaluateRegistryAccess("access-token");
|
|
await vi.advanceTimersByTimeAsync(5_000);
|
|
await expect(result).resolves.toMatchObject({
|
|
status: REGISTRY_ACCESS.UNKNOWN,
|
|
});
|
|
vi.useRealTimers();
|
|
});
|
|
});
|