mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-08-21 05:13:00 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8016dba9a | ||
|
|
8ab575f181 |
@@ -23,7 +23,7 @@ vi.mock("@/lib/sentry-breadcrumbs", () => ({
|
||||
|
||||
import { createNewUser, getUserByMe } from "./auth";
|
||||
|
||||
const userMeResponse = (roleAttributes: Record<string, boolean>) => ({
|
||||
const userMeResponse = (roleAttributes: Record<string, unknown>) => ({
|
||||
data: {
|
||||
type: "users",
|
||||
id: "019b1234-5678-7abc-9def-0123456789ab",
|
||||
@@ -43,7 +43,7 @@ const userMeResponse = (roleAttributes: Record<string, boolean>) => ({
|
||||
],
|
||||
});
|
||||
|
||||
const mockUserMe = (roleAttributes: Record<string, boolean>) => {
|
||||
const mockUserMe = (roleAttributes: Record<string, unknown>) => {
|
||||
fetchMock.mockResolvedValue(
|
||||
new Response(JSON.stringify(userMeResponse(roleAttributes)), {
|
||||
status: 200,
|
||||
@@ -154,4 +154,29 @@ describe("auth actions", () => {
|
||||
expect(result.permissions.manage_lighthouse_ai_configuration).toBe(false);
|
||||
expect(result.permissions.manage_users).toBe(true);
|
||||
});
|
||||
|
||||
it("should carry an exact manage_registry permission into the session", async () => {
|
||||
// Given
|
||||
mockUserMe({ manage_registry: true });
|
||||
|
||||
// When
|
||||
const result = await getUserByMe("access-token");
|
||||
|
||||
// Then
|
||||
expect(result.permissions.manage_registry).toBe(true);
|
||||
});
|
||||
|
||||
it.each([undefined, "true", "TRUE", 1])(
|
||||
"should deny a malformed manage_registry value of %j",
|
||||
async (manageRegistry) => {
|
||||
// Given
|
||||
mockUserMe({ manage_registry: manageRegistry });
|
||||
|
||||
// When
|
||||
const result = await getUserByMe("access-token");
|
||||
|
||||
// Then
|
||||
expect(result.permissions.manage_registry).toBe(false);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -183,6 +183,7 @@ export const getUserByMe = async (accessToken: string) => {
|
||||
manage_alerts: userRole.attributes.manage_alerts || false,
|
||||
manage_lighthouse_ai_configuration:
|
||||
userRole.attributes.manage_lighthouse_ai_configuration || false,
|
||||
manage_registry: userRole.attributes.manage_registry === true,
|
||||
unlimited_visibility: userRole.attributes.unlimited_visibility || false,
|
||||
};
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ const makeRoleFormData = () => {
|
||||
formData.set("manage_scans", "false");
|
||||
formData.set("manage_alerts", "true");
|
||||
formData.set("manage_lighthouse_ai_configuration", "true");
|
||||
formData.set("manage_registry", "true");
|
||||
formData.set("unlimited_visibility", "false");
|
||||
return formData;
|
||||
};
|
||||
@@ -73,6 +74,36 @@ describe("role actions", () => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
it("includes manage_registry when creating and updating a role in Prowler Cloud", async () => {
|
||||
// Given
|
||||
vi.stubEnv("UI_CLOUD_ENABLED", "true");
|
||||
|
||||
// When
|
||||
await addRole(makeRoleFormData());
|
||||
const createAttributes = lastRequestBody().data.attributes;
|
||||
await updateRole(makeRoleFormData(), "role-1");
|
||||
const updateAttributes = lastRequestBody().data.attributes;
|
||||
|
||||
// Then
|
||||
expect(createAttributes.manage_registry).toBe(true);
|
||||
expect(updateAttributes.manage_registry).toBe(true);
|
||||
});
|
||||
|
||||
it("omits manage_registry when creating and updating a role outside Prowler Cloud", async () => {
|
||||
// Given
|
||||
vi.stubEnv("UI_CLOUD_ENABLED", "false");
|
||||
|
||||
// When
|
||||
await addRole(makeRoleFormData());
|
||||
const createAttributes = lastRequestBody().data.attributes;
|
||||
await updateRole(makeRoleFormData(), "role-1");
|
||||
const updateAttributes = lastRequestBody().data.attributes;
|
||||
|
||||
// Then
|
||||
expect(createAttributes).not.toHaveProperty("manage_registry");
|
||||
expect(updateAttributes).not.toHaveProperty("manage_registry");
|
||||
});
|
||||
|
||||
it("includes manage_alerts when creating a role in Prowler Cloud", async () => {
|
||||
// Given
|
||||
vi.stubEnv("UI_CLOUD_ENABLED", "true");
|
||||
|
||||
@@ -116,6 +116,8 @@ export const addRole = async (formData: FormData) => {
|
||||
formData.get("manage_alerts") === "true";
|
||||
payload.data.attributes.manage_lighthouse_ai_configuration =
|
||||
formData.get("manage_lighthouse_ai_configuration") === "true";
|
||||
payload.data.attributes.manage_registry =
|
||||
formData.get("manage_registry") === "true";
|
||||
}
|
||||
|
||||
// Add provider groups relationships only if there are items
|
||||
@@ -175,6 +177,8 @@ export const updateRole = async (formData: FormData, roleId: string) => {
|
||||
formData.get("manage_alerts") === "true";
|
||||
payload.data.attributes.manage_lighthouse_ai_configuration =
|
||||
formData.get("manage_lighthouse_ai_configuration") === "true";
|
||||
payload.data.attributes.manage_registry =
|
||||
formData.get("manage_registry") === "true";
|
||||
}
|
||||
|
||||
// Add provider groups relationships only if there are items
|
||||
|
||||
@@ -36,12 +36,14 @@ const RESTRICTED_PERMISSIONS: RolePermissionAttributes = {
|
||||
manage_scans: false,
|
||||
manage_integrations: false,
|
||||
manage_alerts: false,
|
||||
manage_registry: false,
|
||||
unlimited_visibility: false,
|
||||
};
|
||||
|
||||
const ELEVATED_PERMISSIONS: RolePermissionAttributes = {
|
||||
...RESTRICTED_PERMISSIONS,
|
||||
manage_users: true,
|
||||
manage_registry: true,
|
||||
manage_scans: true,
|
||||
};
|
||||
|
||||
@@ -141,6 +143,25 @@ describe("authConfig JWT callback", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should default manage_registry to false when a sign-in user omits it", async () => {
|
||||
// Given
|
||||
const jwtCallback = authConfig.callbacks?.jwt;
|
||||
if (!jwtCallback) throw new Error("JWT callback is not configured");
|
||||
|
||||
// When
|
||||
const result = await jwtCallback({
|
||||
token: {},
|
||||
account: {} as Parameters<typeof jwtCallback>[0]["account"],
|
||||
user: {
|
||||
accessToken: "access-token",
|
||||
refreshToken: "refresh-token",
|
||||
} as Parameters<typeof jwtCallback>[0]["user"],
|
||||
});
|
||||
|
||||
// Then
|
||||
expect(result.user?.permissions.manage_registry).toBe(false);
|
||||
});
|
||||
|
||||
it("should report a tenant switch failure while preserving the current session", async () => {
|
||||
// Given
|
||||
vi.spyOn(console, "warn").mockImplementation(() => undefined);
|
||||
|
||||
@@ -55,6 +55,7 @@ const DEFAULT_PERMISSIONS: RolePermissionAttributes = {
|
||||
manage_billing: false,
|
||||
manage_alerts: false,
|
||||
manage_lighthouse_ai_configuration: false,
|
||||
manage_registry: false,
|
||||
unlimited_visibility: false,
|
||||
};
|
||||
|
||||
|
||||
@@ -68,6 +68,11 @@ vi.mock("@/lib", () => ({
|
||||
description:
|
||||
"Allows configuring Lighthouse AI, including its provider credentials, default model and business context",
|
||||
},
|
||||
{
|
||||
field: "manage_registry",
|
||||
label: "Manage Registry",
|
||||
description: "Allows managing tenant Registry credentials and artifacts",
|
||||
},
|
||||
{
|
||||
field: "manage_billing",
|
||||
label: "Manage Billing",
|
||||
@@ -147,9 +152,25 @@ describe("AddRoleForm", () => {
|
||||
// Then
|
||||
expect(screen.queryByText("Manage Alerts")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Manage Lighthouse AI")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Manage Registry")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Manage Billing")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("submits manage_registry when granted in Prowler Cloud", async () => {
|
||||
// Given
|
||||
vi.stubEnv("UI_CLOUD_ENABLED", "true");
|
||||
const user = userEvent.setup();
|
||||
render(<AddRoleForm groups={[]} />);
|
||||
|
||||
// When
|
||||
await user.type(screen.getByPlaceholderText("Enter role name"), "New role");
|
||||
await user.click(screen.getByRole("checkbox", { name: "Manage Registry" }));
|
||||
await user.click(screen.getByRole("button", { name: "Add Role" }));
|
||||
|
||||
// Then
|
||||
expect(submittedFormData().get("manage_registry")).toBe("true");
|
||||
});
|
||||
|
||||
it("submits manage_lighthouse_ai_configuration when granted in Prowler Cloud", async () => {
|
||||
// Given
|
||||
vi.stubEnv("UI_CLOUD_ENABLED", "true");
|
||||
@@ -193,6 +214,7 @@ describe("AddRoleForm", () => {
|
||||
expect(submittedFormData().has("manage_lighthouse_ai_configuration")).toBe(
|
||||
false,
|
||||
);
|
||||
expect(submittedFormData().has("manage_registry")).toBe(false);
|
||||
});
|
||||
|
||||
it("navigates back to roles when cancel is clicked", async () => {
|
||||
|
||||
@@ -28,6 +28,7 @@ export const AddRoleForm = ({ groups }: { groups: RoleGroupOption[] }) => {
|
||||
manage_billing: false,
|
||||
manage_alerts: false,
|
||||
manage_lighthouse_ai_configuration: false,
|
||||
manage_registry: false,
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -56,6 +57,7 @@ export const AddRoleForm = ({ groups }: { groups: RoleGroupOption[] }) => {
|
||||
"manage_lighthouse_ai_configuration",
|
||||
String(values.manage_lighthouse_ai_configuration),
|
||||
);
|
||||
formData.append("manage_registry", String(values.manage_registry));
|
||||
}
|
||||
|
||||
if (values.groups && values.groups.length > 0) {
|
||||
|
||||
@@ -68,6 +68,11 @@ vi.mock("@/lib", () => ({
|
||||
description:
|
||||
"Allows configuring Lighthouse AI, including its provider credentials, default model and business context",
|
||||
},
|
||||
{
|
||||
field: "manage_registry",
|
||||
label: "Manage Registry",
|
||||
description: "Allows managing tenant Registry credentials and artifacts",
|
||||
},
|
||||
{
|
||||
field: "manage_billing",
|
||||
label: "Manage Billing",
|
||||
@@ -97,9 +102,11 @@ beforeAll(() => {
|
||||
|
||||
const roleData = ({
|
||||
manageProviders = false,
|
||||
manageRegistry = false,
|
||||
unlimitedVisibility = false,
|
||||
}: {
|
||||
manageProviders?: boolean;
|
||||
manageRegistry?: boolean;
|
||||
unlimitedVisibility?: boolean;
|
||||
} = {}) => ({
|
||||
data: {
|
||||
@@ -109,6 +116,7 @@ const roleData = ({
|
||||
manage_account: false,
|
||||
manage_providers: manageProviders,
|
||||
manage_integrations: false,
|
||||
manage_registry: manageRegistry,
|
||||
manage_scans: false,
|
||||
unlimited_visibility: unlimitedVisibility,
|
||||
groups: [],
|
||||
@@ -139,6 +147,19 @@ describe("EditRoleForm", () => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
it("retains manage_registry when updating a role in Prowler Cloud", async () => {
|
||||
// Given
|
||||
vi.stubEnv("UI_CLOUD_ENABLED", "true");
|
||||
const user = userEvent.setup();
|
||||
renderEditRoleForm({ manageRegistry: true });
|
||||
|
||||
// When
|
||||
await user.click(screen.getByRole("button", { name: "Update Role" }));
|
||||
|
||||
// Then
|
||||
expect(submittedFormData().get("manage_registry")).toBe("true");
|
||||
});
|
||||
|
||||
it("submits manage_lighthouse_ai_configuration when granted in Prowler Cloud", async () => {
|
||||
// Given
|
||||
vi.stubEnv("UI_CLOUD_ENABLED", "true");
|
||||
@@ -186,6 +207,7 @@ describe("EditRoleForm", () => {
|
||||
expect(submittedFormData().has("manage_lighthouse_ai_configuration")).toBe(
|
||||
false,
|
||||
);
|
||||
expect(submittedFormData().has("manage_registry")).toBe(false);
|
||||
});
|
||||
|
||||
it("shows the subtle Unlimited Visibility description inside Visibility", () => {
|
||||
|
||||
@@ -35,6 +35,9 @@ export const EditRoleForm = ({
|
||||
|
||||
const defaultValues: DefaultValues<RoleFormValues> = {
|
||||
...roleData.data.attributes,
|
||||
...(isCloudEnvironment && {
|
||||
manage_registry: roleData.data.attributes.manage_registry ?? false,
|
||||
}),
|
||||
groups:
|
||||
roleData.data.relationships?.provider_groups?.data.map((g) => g.id) || [],
|
||||
};
|
||||
@@ -62,6 +65,7 @@ export const EditRoleForm = ({
|
||||
updatedFields.manage_alerts = values.manage_alerts;
|
||||
updatedFields.manage_lighthouse_ai_configuration =
|
||||
values.manage_lighthouse_ai_configuration;
|
||||
updatedFields.manage_registry = values.manage_registry;
|
||||
}
|
||||
|
||||
if (
|
||||
|
||||
@@ -15,6 +15,7 @@ export function useAuth() {
|
||||
manage_billing: false,
|
||||
manage_alerts: false,
|
||||
manage_lighthouse_ai_configuration: false,
|
||||
manage_registry: false,
|
||||
unlimited_visibility: false,
|
||||
};
|
||||
|
||||
|
||||
@@ -141,6 +141,19 @@ describe("getErrorMessage", () => {
|
||||
});
|
||||
|
||||
describe("permissionFormFields", () => {
|
||||
it("describes Manage Registry", () => {
|
||||
// Given
|
||||
const field = permissionFormFields.find(
|
||||
({ field }) => field === "manage_registry",
|
||||
);
|
||||
|
||||
// When / Then
|
||||
expect(field).toMatchObject({
|
||||
label: "Manage Registry",
|
||||
description: expect.stringContaining("Registry"),
|
||||
});
|
||||
});
|
||||
|
||||
it("describes Unlimited Visibility as organization-wide", () => {
|
||||
// Given
|
||||
const field = permissionFormFields.find(
|
||||
|
||||
@@ -475,6 +475,11 @@ export const permissionFormFields: PermissionInfo[] = [
|
||||
description:
|
||||
"Allows configuring Lighthouse AI, including its provider credentials, default model and business context",
|
||||
},
|
||||
{
|
||||
field: "manage_registry",
|
||||
label: "Manage Registry",
|
||||
description: "Allows managing tenant Registry credentials and artifacts",
|
||||
},
|
||||
|
||||
{
|
||||
field: "manage_billing",
|
||||
|
||||
@@ -13,6 +13,7 @@ const attributes = {
|
||||
manage_billing: false,
|
||||
manage_alerts: true,
|
||||
manage_lighthouse_ai_configuration: true,
|
||||
manage_registry: true,
|
||||
unlimited_visibility: false,
|
||||
} satisfies RolePermissionAttributes;
|
||||
|
||||
@@ -21,6 +22,34 @@ describe("getRolePermissions", () => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
it("includes Manage Registry in Prowler Cloud when role attributes provide it", () => {
|
||||
// Given
|
||||
vi.stubEnv("UI_CLOUD_ENABLED", "true");
|
||||
|
||||
// When
|
||||
const permissions = getRolePermissions(attributes);
|
||||
|
||||
// Then
|
||||
expect(permissions).toContainEqual({
|
||||
key: "manage_registry",
|
||||
label: "Manage Registry",
|
||||
enabled: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("hides Manage Registry outside Prowler Cloud", () => {
|
||||
// Given
|
||||
vi.stubEnv("UI_CLOUD_ENABLED", "false");
|
||||
|
||||
// When
|
||||
const permissions = getRolePermissions(attributes);
|
||||
|
||||
// Then
|
||||
expect(
|
||||
permissions.some((permission) => permission.key === "manage_registry"),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("includes Manage Alerts in Prowler Cloud when role attributes provide it", () => {
|
||||
// Given
|
||||
vi.stubEnv("UI_CLOUD_ENABLED", "true");
|
||||
|
||||
@@ -72,6 +72,11 @@ export const getRolePermissions = (attributes: RolePermissionAttributes) => {
|
||||
label: "Manage Lighthouse AI",
|
||||
enabled: attributes.manage_lighthouse_ai_configuration ?? false,
|
||||
},
|
||||
{
|
||||
key: "manage_registry",
|
||||
label: "Manage Registry",
|
||||
enabled: attributes.manage_registry === true,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ const hiddenOutsideCloudFields = [
|
||||
"manage_billing",
|
||||
"manage_alerts",
|
||||
"manage_lighthouse_ai_configuration",
|
||||
"manage_registry",
|
||||
];
|
||||
|
||||
export const getVisiblePermissionFormFields = (isCloudEnvironment: boolean) =>
|
||||
|
||||
@@ -111,6 +111,23 @@ describe("readBoolEnv", () => {
|
||||
expect(readBoolEnv("UI_SENTRY_ENABLED")).toBe(false);
|
||||
});
|
||||
|
||||
it("defaults UI_REGISTRY_ENABLED to disabled and enables its true value", () => {
|
||||
const cases: Array<[string | undefined, boolean]> = [
|
||||
[undefined, false],
|
||||
["true", true],
|
||||
["TRUE", false],
|
||||
["1", false],
|
||||
];
|
||||
|
||||
for (const [value, enabled] of cases) {
|
||||
// Given
|
||||
vi.stubEnv("UI_REGISTRY_ENABLED", value);
|
||||
|
||||
// When / Then
|
||||
expect(readBoolEnv("UI_REGISTRY_ENABLED")).toBe(enabled);
|
||||
}
|
||||
});
|
||||
|
||||
it('is false for other truthy-looking values ("TRUE", "1", "yes")', () => {
|
||||
for (const value of ["TRUE", "1", "yes"]) {
|
||||
// Given
|
||||
|
||||
Vendored
+1
@@ -30,6 +30,7 @@ declare global {
|
||||
|
||||
// Prowler Cloud deployment flag — runtime read (server env, client island).
|
||||
UI_CLOUD_ENABLED?: "true" | "false";
|
||||
UI_REGISTRY_ENABLED?: "true" | "false";
|
||||
|
||||
CLOUD_BILLING_ENABLED?: "legacy" | "metronome" | "false";
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
addCredentialsRoleFormSchema,
|
||||
addProviderFormSchema,
|
||||
KUBECONFIG_UNSUPPORTED_COMMAND_AUTHENTICATION_ERROR,
|
||||
roleFormSchema,
|
||||
samlConfigFormSchema,
|
||||
} from "./formSchemas";
|
||||
|
||||
@@ -20,6 +21,30 @@ const BASE_AWS_ROLE_VALUES = {
|
||||
[ProviderCredentialFields.CREDENTIALS_TYPE]: "access-secret-key",
|
||||
} as const;
|
||||
|
||||
describe("roleFormSchema", () => {
|
||||
it("defaults manage_registry to false", () => {
|
||||
// Given / When
|
||||
const result = roleFormSchema.parse({ name: "Registry manager" });
|
||||
|
||||
// Then
|
||||
expect(result.manage_registry).toBe(false);
|
||||
});
|
||||
|
||||
it.each(["true", 1, null])(
|
||||
"rejects malformed manage_registry values of %j",
|
||||
(manageRegistry) => {
|
||||
// Given / When
|
||||
const result = roleFormSchema.safeParse({
|
||||
name: "Registry manager",
|
||||
manage_registry: manageRegistry,
|
||||
});
|
||||
|
||||
// Then
|
||||
expect(result.success).toBe(false);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("addCredentialsRoleFormSchema", () => {
|
||||
it("accepts AWS role credentials when access and secret keys are present", () => {
|
||||
const schema = addCredentialsRoleFormSchema("aws");
|
||||
|
||||
@@ -56,6 +56,7 @@ export const roleFormSchema = z.object({
|
||||
manage_scans: z.boolean().default(false),
|
||||
manage_alerts: z.boolean().default(false),
|
||||
manage_lighthouse_ai_configuration: z.boolean().default(false),
|
||||
manage_registry: z.boolean().default(false),
|
||||
unlimited_visibility: z.boolean().default(false),
|
||||
groups: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
@@ -91,6 +91,7 @@ export const PERMISSION_KEY = {
|
||||
MANAGE_BILLING: "manage_billing",
|
||||
MANAGE_ALERTS: "manage_alerts",
|
||||
MANAGE_LIGHTHOUSE_AI_CONFIGURATION: "manage_lighthouse_ai_configuration",
|
||||
MANAGE_REGISTRY: "manage_registry",
|
||||
UNLIMITED_VISIBILITY: "unlimited_visibility",
|
||||
} as const;
|
||||
|
||||
@@ -123,6 +124,7 @@ export interface RoleDetail {
|
||||
manage_billing?: boolean;
|
||||
manage_alerts?: boolean;
|
||||
manage_lighthouse_ai_configuration?: boolean;
|
||||
manage_registry?: boolean;
|
||||
unlimited_visibility: boolean;
|
||||
permission_state?: string;
|
||||
inserted_at?: string;
|
||||
|
||||
Reference in New Issue
Block a user