Add rbac permissioning support for ssh hosts, render access tree for secrets projects only

This commit is contained in:
Tuan Dang
2025-04-08 14:56:05 -07:00
parent bf5e8d8c8b
commit 728c3f56a7
8 changed files with 366 additions and 61 deletions
@@ -18,6 +18,7 @@ import {
ProjectPermissionMemberActions,
ProjectPermissionSecretActions,
ProjectPermissionSecretSyncActions,
ProjectPermissionSshHostActions,
TPermissionCondition,
TPermissionConditionOperators
} from "@app/context/ProjectPermissionContext/types";
@@ -98,6 +99,15 @@ const GroupPolicyActionSchema = z.object({
[ProjectPermissionGroupActions.GrantPrivileges]: z.boolean().optional()
});
const SshHostPolicyActionSchema = z.object({
[ProjectPermissionSshHostActions.Read]: z.boolean().optional(),
[ProjectPermissionSshHostActions.Create]: z.boolean().optional(),
[ProjectPermissionSshHostActions.Edit]: z.boolean().optional(),
[ProjectPermissionSshHostActions.Delete]: z.boolean().optional(),
[ProjectPermissionSshHostActions.IssueUserCert]: z.boolean().optional(),
[ProjectPermissionSshHostActions.IssueHostCert]: z.boolean().optional()
});
const SecretRollbackPolicyActionSchema = z.object({
read: z.boolean().optional(),
create: z.boolean().optional()
@@ -205,7 +215,12 @@ export const projectRoleFormSchema = z.object({
),
[ProjectPermissionSub.SshCertificates]: GeneralPolicyActionSchema.array().default([]),
[ProjectPermissionSub.SshCertificateTemplates]: GeneralPolicyActionSchema.array().default([]),
[ProjectPermissionSub.SshHosts]: GeneralPolicyActionSchema.array().default([]),
[ProjectPermissionSub.SshHosts]: SshHostPolicyActionSchema.extend({
inverted: z.boolean().optional(),
conditions: ConditionSchema
})
.array()
.default([]),
[ProjectPermissionSub.SecretApproval]: GeneralPolicyActionSchema.array().default([]),
[ProjectPermissionSub.SecretRollback]: SecretRollbackPolicyActionSchema.array().default([]),
[ProjectPermissionSub.Project]: WorkspacePolicyActionSchema.array().default([]),
@@ -227,7 +242,8 @@ type TConditionalFields =
| ProjectPermissionSub.SecretFolders
| ProjectPermissionSub.SecretImports
| ProjectPermissionSub.DynamicSecrets
| ProjectPermissionSub.Identity;
| ProjectPermissionSub.Identity
| ProjectPermissionSub.SshHosts;
export const isConditionalSubjects = (
subject: ProjectPermissionSub
@@ -236,7 +252,8 @@ export const isConditionalSubjects = (
subject === ProjectPermissionSub.DynamicSecrets ||
subject === ProjectPermissionSub.SecretImports ||
subject === ProjectPermissionSub.SecretFolders ||
subject === ProjectPermissionSub.Identity;
subject === ProjectPermissionSub.Identity ||
subject === ProjectPermissionSub.SshHosts;
const convertCaslConditionToFormOperator = (caslConditions: TPermissionCondition) => {
const formConditions: z.infer<typeof ConditionSchema> = [];
@@ -293,7 +310,6 @@ export const rolePermission2Form = (permissions: TProjectPermission[] = []) => {
ProjectPermissionSub.Tags,
ProjectPermissionSub.SecretRotation,
ProjectPermissionSub.Kms,
ProjectPermissionSub.SshHosts,
ProjectPermissionSub.SshCertificateTemplates,
ProjectPermissionSub.SshCertificateAuthorities,
ProjectPermissionSub.SshCertificates
@@ -541,7 +557,33 @@ export const rolePermission2Form = (permissions: TProjectPermission[] = []) => {
if (canRemoveSecrets)
formVal[subject]![0][ProjectPermissionSecretSyncActions.RemoveSecrets] = true;
}
if (subject === ProjectPermissionSub.SshHosts) {
const canRead = action.includes(ProjectPermissionSshHostActions.Read);
const canEdit = action.includes(ProjectPermissionSshHostActions.Edit);
const canDelete = action.includes(ProjectPermissionSshHostActions.Delete);
const canCreate = action.includes(ProjectPermissionSshHostActions.Create);
const canIssueUserCert = action.includes(ProjectPermissionSshHostActions.IssueUserCert);
const canIssueHostCert = action.includes(ProjectPermissionSshHostActions.IssueHostCert);
if (!formVal[subject]) formVal[subject] = [{ conditions: [] }];
if (canRead) formVal[subject]![0][ProjectPermissionSshHostActions.Read] = true;
if (canEdit) formVal[subject]![0][ProjectPermissionSshHostActions.Edit] = true;
if (canDelete) formVal[subject]![0][ProjectPermissionSshHostActions.Delete] = true;
if (canCreate) formVal[subject]![0][ProjectPermissionSshHostActions.Create] = true;
if (canIssueUserCert)
formVal[subject]![0][ProjectPermissionSshHostActions.IssueUserCert] = true;
if (canIssueHostCert)
formVal[subject]![0][ProjectPermissionSshHostActions.IssueHostCert] = true;
formVal[subject]![0].conditions = conditions
? convertCaslConditionToFormOperator(conditions)
: [];
formVal[subject]![0].inverted = inverted;
}
});
return formVal;
};
@@ -868,10 +910,12 @@ export const PROJECT_PERMISSION_OBJECT: TProjectPermissionObject = {
[ProjectPermissionSub.SshHosts]: {
title: "SSH Hosts",
actions: [
{ label: "Read", value: "read" },
{ label: "Create", value: "create" },
{ label: "Modify", value: "edit" },
{ label: "Remove", value: "delete" }
{ label: "Read", value: ProjectPermissionSshHostActions.Read },
{ label: "Create", value: ProjectPermissionSshHostActions.Create },
{ label: "Modify", value: ProjectPermissionSshHostActions.Edit },
{ label: "Remove", value: ProjectPermissionSshHostActions.Delete },
{ label: "Connect", value: ProjectPermissionSshHostActions.IssueUserCert },
{ label: "Issue Host Certificate", value: ProjectPermissionSshHostActions.IssueHostCert }
]
},
[ProjectPermissionSub.PkiCollections]: {