mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Add secret share permissions
This commit is contained in:
@@ -32,6 +32,10 @@ export enum OrgPermissionAdminConsoleAction {
|
|||||||
AccessAllProjects = "access-all-projects"
|
AccessAllProjects = "access-all-projects"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum OrgPermissionSecretShareAction {
|
||||||
|
ManageSettings = "manage-settings"
|
||||||
|
}
|
||||||
|
|
||||||
export enum OrgPermissionGatewayActions {
|
export enum OrgPermissionGatewayActions {
|
||||||
// is there a better word for this. This mean can an identity be a gateway
|
// is there a better word for this. This mean can an identity be a gateway
|
||||||
CreateGateways = "create-gateways",
|
CreateGateways = "create-gateways",
|
||||||
@@ -59,7 +63,8 @@ export enum OrgPermissionSubjects {
|
|||||||
ProjectTemplates = "project-templates",
|
ProjectTemplates = "project-templates",
|
||||||
AppConnections = "app-connections",
|
AppConnections = "app-connections",
|
||||||
Kmip = "kmip",
|
Kmip = "kmip",
|
||||||
Gateway = "gateway"
|
Gateway = "gateway",
|
||||||
|
SecretShare = "secret-share"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AppConnectionSubjectFields = {
|
export type AppConnectionSubjectFields = {
|
||||||
@@ -91,7 +96,8 @@ export type OrgPermissionSet =
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
| [OrgPermissionAdminConsoleAction, OrgPermissionSubjects.AdminConsole]
|
| [OrgPermissionAdminConsoleAction, OrgPermissionSubjects.AdminConsole]
|
||||||
| [OrgPermissionKmipActions, OrgPermissionSubjects.Kmip];
|
| [OrgPermissionKmipActions, OrgPermissionSubjects.Kmip]
|
||||||
|
| [OrgPermissionSecretShareAction, OrgPermissionSubjects.SecretShare];
|
||||||
|
|
||||||
const AppConnectionConditionSchema = z
|
const AppConnectionConditionSchema = z
|
||||||
.object({
|
.object({
|
||||||
@@ -185,6 +191,12 @@ export const OrgPermissionSchema = z.discriminatedUnion("subject", [
|
|||||||
"Describe what action an entity can take."
|
"Describe what action an entity can take."
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z.literal(OrgPermissionSubjects.SecretShare).describe("The entity this permission pertains to."),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionSecretShareAction).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
z.object({
|
z.object({
|
||||||
subject: z.literal(OrgPermissionSubjects.Kmip).describe("The entity this permission pertains to."),
|
subject: z.literal(OrgPermissionSubjects.Kmip).describe("The entity this permission pertains to."),
|
||||||
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionKmipActions).describe(
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionKmipActions).describe(
|
||||||
@@ -292,6 +304,8 @@ const buildAdminPermission = () => {
|
|||||||
// the proxy assignment is temporary in order to prevent "more privilege" error during role assignment to MI
|
// the proxy assignment is temporary in order to prevent "more privilege" error during role assignment to MI
|
||||||
can(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
can(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
||||||
|
|
||||||
|
can(OrgPermissionSecretShareAction.ManageSettings, OrgPermissionSubjects.SecretShare);
|
||||||
|
|
||||||
return rules;
|
return rules;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -34,13 +34,18 @@ export enum OrgPermissionSubjects {
|
|||||||
ProjectTemplates = "project-templates",
|
ProjectTemplates = "project-templates",
|
||||||
AppConnections = "app-connections",
|
AppConnections = "app-connections",
|
||||||
Kmip = "kmip",
|
Kmip = "kmip",
|
||||||
Gateway = "gateway"
|
Gateway = "gateway",
|
||||||
|
SecretShare = "secret-share"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum OrgPermissionAdminConsoleAction {
|
export enum OrgPermissionAdminConsoleAction {
|
||||||
AccessAllProjects = "access-all-projects"
|
AccessAllProjects = "access-all-projects"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum OrgPermissionSecretShareAction {
|
||||||
|
ManageSettings = "manage-settings"
|
||||||
|
}
|
||||||
|
|
||||||
export enum OrgPermissionAppConnectionActions {
|
export enum OrgPermissionAppConnectionActions {
|
||||||
Read = "read",
|
Read = "read",
|
||||||
Create = "create",
|
Create = "create",
|
||||||
@@ -78,7 +83,8 @@ export type OrgPermissionSet =
|
|||||||
| [OrgPermissionActions, OrgPermissionSubjects.ProjectTemplates]
|
| [OrgPermissionActions, OrgPermissionSubjects.ProjectTemplates]
|
||||||
| [OrgPermissionAppConnectionActions, OrgPermissionSubjects.AppConnections]
|
| [OrgPermissionAppConnectionActions, OrgPermissionSubjects.AppConnections]
|
||||||
| [OrgPermissionKmipActions, OrgPermissionSubjects.Kmip]
|
| [OrgPermissionKmipActions, OrgPermissionSubjects.Kmip]
|
||||||
| [OrgGatewayPermissionActions, OrgPermissionSubjects.Gateway];
|
| [OrgGatewayPermissionActions, OrgPermissionSubjects.Gateway]
|
||||||
|
| [OrgPermissionSecretShareAction, OrgPermissionSubjects.SecretShare];
|
||||||
// TODO(scott): add back once org UI refactored
|
// TODO(scott): add back once org UI refactored
|
||||||
// | [
|
// | [
|
||||||
// OrgPermissionAppConnectionActions,
|
// OrgPermissionAppConnectionActions,
|
||||||
|
|||||||
@@ -8,12 +8,8 @@ import { twMerge } from "tailwind-merge";
|
|||||||
import { CreateOrgModal } from "@app/components/organization/CreateOrgModal";
|
import { CreateOrgModal } from "@app/components/organization/CreateOrgModal";
|
||||||
import { Banner } from "@app/components/page-frames/Banner";
|
import { Banner } from "@app/components/page-frames/Banner";
|
||||||
import { BreadcrumbContainer, TBreadcrumbFormat } from "@app/components/v2";
|
import { BreadcrumbContainer, TBreadcrumbFormat } from "@app/components/v2";
|
||||||
import {
|
import { OrgPermissionSubjects, useOrgPermission, useServerConfig } from "@app/context";
|
||||||
OrgPermissionActions,
|
import { OrgPermissionSecretShareAction } from "@app/context/OrgPermissionContext/types";
|
||||||
OrgPermissionSubjects,
|
|
||||||
useOrgPermission,
|
|
||||||
useServerConfig
|
|
||||||
} from "@app/context";
|
|
||||||
import { usePopUp } from "@app/hooks";
|
import { usePopUp } from "@app/hooks";
|
||||||
|
|
||||||
import { InsecureConnectionBanner } from "./components/InsecureConnectionBanner";
|
import { InsecureConnectionBanner } from "./components/InsecureConnectionBanner";
|
||||||
@@ -28,8 +24,8 @@ export const OrganizationLayout = () => {
|
|||||||
const { permission } = useOrgPermission();
|
const { permission } = useOrgPermission();
|
||||||
|
|
||||||
const shouldShowProductsSidebar = permission.can(
|
const shouldShowProductsSidebar = permission.can(
|
||||||
OrgPermissionActions.Edit,
|
OrgPermissionSecretShareAction.ManageSettings,
|
||||||
OrgPermissionSubjects.Settings
|
OrgPermissionSubjects.SecretShare
|
||||||
);
|
);
|
||||||
|
|
||||||
const isOrganizationSpecificPage = location.pathname.startsWith("/organization");
|
const isOrganizationSpecificPage = location.pathname.startsWith("/organization");
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import { OrgPermissionSubjects } from "@app/context";
|
|||||||
import {
|
import {
|
||||||
OrgGatewayPermissionActions,
|
OrgGatewayPermissionActions,
|
||||||
OrgPermissionAppConnectionActions,
|
OrgPermissionAppConnectionActions,
|
||||||
OrgPermissionKmipActions
|
OrgPermissionKmipActions,
|
||||||
|
OrgPermissionSecretShareAction
|
||||||
} from "@app/context/OrgPermissionContext/types";
|
} from "@app/context/OrgPermissionContext/types";
|
||||||
import { TPermission } from "@app/hooks/api/roles/types";
|
import { TPermission } from "@app/hooks/api/roles/types";
|
||||||
|
|
||||||
@@ -50,6 +51,12 @@ const adminConsolePermissionSchmea = z
|
|||||||
})
|
})
|
||||||
.optional();
|
.optional();
|
||||||
|
|
||||||
|
const secretSharingPermissionSchema = z
|
||||||
|
.object({
|
||||||
|
[OrgPermissionSecretShareAction.ManageSettings]: z.boolean().optional()
|
||||||
|
})
|
||||||
|
.optional();
|
||||||
|
|
||||||
export const formSchema = z.object({
|
export const formSchema = z.object({
|
||||||
name: z.string().trim(),
|
name: z.string().trim(),
|
||||||
description: z.string().trim().optional(),
|
description: z.string().trim().optional(),
|
||||||
@@ -83,7 +90,8 @@ export const formSchema = z.object({
|
|||||||
[OrgPermissionSubjects.ProjectTemplates]: generalPermissionSchema,
|
[OrgPermissionSubjects.ProjectTemplates]: generalPermissionSchema,
|
||||||
"app-connections": appConnectionsPermissionSchema,
|
"app-connections": appConnectionsPermissionSchema,
|
||||||
kmip: kmipPermissionSchema,
|
kmip: kmipPermissionSchema,
|
||||||
gateway: orgGatewayPermissionSchema
|
gateway: orgGatewayPermissionSchema,
|
||||||
|
"secret-share": secretSharingPermissionSchema
|
||||||
})
|
})
|
||||||
.optional()
|
.optional()
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
import { useEffect, useMemo } from "react";
|
||||||
|
import { Control, Controller, UseFormSetValue, useWatch } from "react-hook-form";
|
||||||
|
import { faChevronDown, faChevronRight } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
|
import { createNotification } from "@app/components/notifications";
|
||||||
|
import { Checkbox, Select, SelectItem, Td, Tr } from "@app/components/v2";
|
||||||
|
import { useToggle } from "@app/hooks";
|
||||||
|
|
||||||
|
import { TFormSchema } from "../OrgRoleModifySection.utils";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isEditable: boolean;
|
||||||
|
setValue: UseFormSetValue<TFormSchema>;
|
||||||
|
control: Control<TFormSchema>;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Permission {
|
||||||
|
NoAccess = "no-access",
|
||||||
|
Custom = "custom"
|
||||||
|
}
|
||||||
|
|
||||||
|
const PERMISSION_ACTIONS = [{ action: "manage-settings", label: "Manage settings" }] as const;
|
||||||
|
|
||||||
|
export const OrgPermissionSecretShareRow = ({ isEditable, control, setValue }: Props) => {
|
||||||
|
const [isRowExpanded, setIsRowExpanded] = useToggle();
|
||||||
|
const [isCustom, setIsCustom] = useToggle();
|
||||||
|
|
||||||
|
const rule = useWatch({
|
||||||
|
control,
|
||||||
|
name: "permissions.secret-share"
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedPermissionCategory = useMemo(() => {
|
||||||
|
if (rule?.["manage-settings"]) {
|
||||||
|
return Permission.Custom;
|
||||||
|
}
|
||||||
|
return Permission.NoAccess;
|
||||||
|
}, [rule, isCustom]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedPermissionCategory === Permission.Custom) setIsCustom.on();
|
||||||
|
else setIsCustom.off();
|
||||||
|
}, [selectedPermissionCategory]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const isRowCustom = selectedPermissionCategory === Permission.Custom;
|
||||||
|
if (isRowCustom) {
|
||||||
|
setIsRowExpanded.on();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handlePermissionChange = (val: Permission) => {
|
||||||
|
if (!val) return;
|
||||||
|
if (val === Permission.Custom) {
|
||||||
|
setIsRowExpanded.on();
|
||||||
|
setIsCustom.on();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIsCustom.off();
|
||||||
|
|
||||||
|
if (val === Permission.NoAccess) {
|
||||||
|
setValue("permissions.secret-share", { "manage-settings": false }, { shouldDirty: true });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Tr
|
||||||
|
className="h-10 cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700"
|
||||||
|
onClick={() => setIsRowExpanded.toggle()}
|
||||||
|
>
|
||||||
|
<Td>
|
||||||
|
<FontAwesomeIcon icon={isRowExpanded ? faChevronDown : faChevronRight} />
|
||||||
|
</Td>
|
||||||
|
<Td>Secret Share</Td>
|
||||||
|
<Td>
|
||||||
|
<Select
|
||||||
|
value={selectedPermissionCategory}
|
||||||
|
className="w-40 bg-mineshaft-600"
|
||||||
|
dropdownContainerClassName="border border-mineshaft-600 bg-mineshaft-800"
|
||||||
|
onValueChange={handlePermissionChange}
|
||||||
|
isDisabled={!isEditable}
|
||||||
|
>
|
||||||
|
<SelectItem value={Permission.NoAccess}>No Access</SelectItem>
|
||||||
|
<SelectItem value={Permission.Custom}>Custom</SelectItem>
|
||||||
|
</Select>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
{isRowExpanded && (
|
||||||
|
<Tr>
|
||||||
|
<Td
|
||||||
|
colSpan={3}
|
||||||
|
className={`bg-bunker-600 px-0 py-0 ${isRowExpanded && "border-mineshaft-500 p-8"}`}
|
||||||
|
>
|
||||||
|
<div className="grid grid-cols-3 gap-4">
|
||||||
|
{PERMISSION_ACTIONS.map(({ action, label }) => {
|
||||||
|
return (
|
||||||
|
<Controller
|
||||||
|
name={`permissions.secret-share.${action}`}
|
||||||
|
key={`permissions.secret-share.${action}`}
|
||||||
|
control={control}
|
||||||
|
render={({ field }) => (
|
||||||
|
<Checkbox
|
||||||
|
isChecked={field.value}
|
||||||
|
onCheckedChange={(e) => {
|
||||||
|
if (!isEditable) {
|
||||||
|
createNotification({
|
||||||
|
type: "error",
|
||||||
|
text: "Failed to update default role"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
field.onChange(e);
|
||||||
|
}}
|
||||||
|
id={`permissions.secret-share.${action}`}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Checkbox>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -74,7 +74,7 @@ type Props = {
|
|||||||
title: string;
|
title: string;
|
||||||
formName: keyof Omit<
|
formName: keyof Omit<
|
||||||
Exclude<TFormSchema["permissions"], undefined>,
|
Exclude<TFormSchema["permissions"], undefined>,
|
||||||
"workspace" | "organization-admin-console" | "kmip" | "gateway"
|
"workspace" | "organization-admin-console" | "kmip" | "gateway" | "secret-share"
|
||||||
>;
|
>;
|
||||||
setValue: UseFormSetValue<TFormSchema>;
|
setValue: UseFormSetValue<TFormSchema>;
|
||||||
control: Control<TFormSchema>;
|
control: Control<TFormSchema>;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
import { OrgPermissionAdminConsoleRow } from "./OrgPermissionAdminConsoleRow";
|
import { OrgPermissionAdminConsoleRow } from "./OrgPermissionAdminConsoleRow";
|
||||||
import { OrgGatewayPermissionRow } from "./OrgPermissionGatewayRow";
|
import { OrgGatewayPermissionRow } from "./OrgPermissionGatewayRow";
|
||||||
import { OrgPermissionKmipRow } from "./OrgPermissionKmipRow";
|
import { OrgPermissionKmipRow } from "./OrgPermissionKmipRow";
|
||||||
|
import { OrgPermissionSecretShareRow } from "./OrgPermissionSecretShareRow";
|
||||||
import { OrgRoleWorkspaceRow } from "./OrgRoleWorkspaceRow";
|
import { OrgRoleWorkspaceRow } from "./OrgRoleWorkspaceRow";
|
||||||
import { RolePermissionRow } from "./RolePermissionRow";
|
import { RolePermissionRow } from "./RolePermissionRow";
|
||||||
|
|
||||||
@@ -100,6 +101,8 @@ export const RolePermissionsSection = ({ roleId }: Props) => {
|
|||||||
|
|
||||||
const onSubmit = async (el: TFormSchema) => {
|
const onSubmit = async (el: TFormSchema) => {
|
||||||
try {
|
try {
|
||||||
|
console.log(el.permissions);
|
||||||
|
console.log(formRolePermission2API(el.permissions));
|
||||||
await updateRole({
|
await updateRole({
|
||||||
orgId,
|
orgId,
|
||||||
id: roleId,
|
id: roleId,
|
||||||
@@ -177,6 +180,11 @@ export const RolePermissionsSection = ({ roleId }: Props) => {
|
|||||||
setValue={setValue}
|
setValue={setValue}
|
||||||
isEditable={isCustomRole}
|
isEditable={isCustomRole}
|
||||||
/>
|
/>
|
||||||
|
<OrgPermissionSecretShareRow
|
||||||
|
control={control}
|
||||||
|
setValue={setValue}
|
||||||
|
isEditable={isCustomRole}
|
||||||
|
/>
|
||||||
<OrgRoleWorkspaceRow
|
<OrgRoleWorkspaceRow
|
||||||
control={control}
|
control={control}
|
||||||
setValue={setValue}
|
setValue={setValue}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
|
|
||||||
import { PageHeader } from "@app/components/v2";
|
import { PageHeader } from "@app/components/v2";
|
||||||
import {
|
import {
|
||||||
OrgPermissionActions,
|
OrgPermissionSecretShareAction,
|
||||||
OrgPermissionSubjects
|
OrgPermissionSubjects
|
||||||
} from "@app/context/OrgPermissionContext/types";
|
} from "@app/context/OrgPermissionContext/types";
|
||||||
import { withPermission } from "@app/hoc";
|
import { withPermission } from "@app/hoc";
|
||||||
@@ -29,7 +29,7 @@ export const SecretSharingSettingsPage = withPermission(
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
action: OrgPermissionActions.Edit,
|
action: OrgPermissionSecretShareAction.ManageSettings,
|
||||||
subject: OrgPermissionSubjects.Settings
|
subject: OrgPermissionSubjects.SecretShare
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user