Merge pull request #3064 from akhilmhdh/fix/secret-path-validation-permission

feat: added validation for secret path in permission
This commit is contained in:
Akhil Mohan
2025-01-29 18:46:38 +05:30
committed by GitHub
3 changed files with 42 additions and 24 deletions
@@ -163,6 +163,27 @@ export type ProjectPermissionSet =
| [ProjectPermissionActions.Create, ProjectPermissionSub.SecretRollback] | [ProjectPermissionActions.Create, ProjectPermissionSub.SecretRollback]
| [ProjectPermissionActions.Edit, ProjectPermissionSub.Kms]; | [ProjectPermissionActions.Edit, ProjectPermissionSub.Kms];
const SECRET_PATH_MISSING_SLASH_ERR_MSG = "Invalid Secret Path; it must start with a '/'";
const SECRET_PATH_PERMISSION_OPERATOR_SCHEMA = z.union([
z.string().refine((val) => val.startsWith("/"), SECRET_PATH_MISSING_SLASH_ERR_MSG),
z
.object({
[PermissionConditionOperators.$EQ]: PermissionConditionSchema[PermissionConditionOperators.$EQ].refine(
(val) => val.startsWith("/"),
SECRET_PATH_MISSING_SLASH_ERR_MSG
),
[PermissionConditionOperators.$NEQ]: PermissionConditionSchema[PermissionConditionOperators.$NEQ].refine(
(val) => val.startsWith("/"),
SECRET_PATH_MISSING_SLASH_ERR_MSG
),
[PermissionConditionOperators.$IN]: PermissionConditionSchema[PermissionConditionOperators.$IN].refine(
(val) => val.every((el) => el.startsWith("/")),
SECRET_PATH_MISSING_SLASH_ERR_MSG
),
[PermissionConditionOperators.$GLOB]: PermissionConditionSchema[PermissionConditionOperators.$GLOB]
})
.partial()
]);
// akhilmhdh: don't modify this for v2 // akhilmhdh: don't modify this for v2
// if you want to update create a new schema // if you want to update create a new schema
const SecretConditionV1Schema = z const SecretConditionV1Schema = z
@@ -177,17 +198,7 @@ const SecretConditionV1Schema = z
}) })
.partial() .partial()
]), ]),
secretPath: z.union([ secretPath: SECRET_PATH_PERMISSION_OPERATOR_SCHEMA
z.string(),
z
.object({
[PermissionConditionOperators.$EQ]: PermissionConditionSchema[PermissionConditionOperators.$EQ],
[PermissionConditionOperators.$NEQ]: PermissionConditionSchema[PermissionConditionOperators.$NEQ],
[PermissionConditionOperators.$IN]: PermissionConditionSchema[PermissionConditionOperators.$IN],
[PermissionConditionOperators.$GLOB]: PermissionConditionSchema[PermissionConditionOperators.$GLOB]
})
.partial()
])
}) })
.partial(); .partial();
@@ -204,17 +215,7 @@ const SecretConditionV2Schema = z
}) })
.partial() .partial()
]), ]),
secretPath: z.union([ secretPath: SECRET_PATH_PERMISSION_OPERATOR_SCHEMA,
z.string(),
z
.object({
[PermissionConditionOperators.$EQ]: PermissionConditionSchema[PermissionConditionOperators.$EQ],
[PermissionConditionOperators.$NEQ]: PermissionConditionSchema[PermissionConditionOperators.$NEQ],
[PermissionConditionOperators.$IN]: PermissionConditionSchema[PermissionConditionOperators.$IN],
[PermissionConditionOperators.$GLOB]: PermissionConditionSchema[PermissionConditionOperators.$GLOB]
})
.partial()
]),
secretName: z.union([ secretName: z.union([
z.string(), z.string(),
z z
@@ -80,6 +80,19 @@ const ConditionSchema = z
return true; return true;
}, },
{ message: "Duplicate operator found for a condition" } { message: "Duplicate operator found for a condition" }
)
.refine(
(val) =>
val
.filter(
(el) => el.lhs === "secretPath" && el.operator !== PermissionConditionOperators.$GLOB
)
.every((el) =>
el.operator === PermissionConditionOperators.$IN
? el.rhs.split(",").every((i) => i.trim().startsWith("/"))
: el.rhs.trim().startsWith("/")
),
{ message: "Invalid Secret Path. Must start with '/'" }
); );
export const projectRoleFormSchema = z.object({ export const projectRoleFormSchema = z.object({
@@ -36,6 +36,10 @@ export const SecretPermissionConditions = ({ position = 0, isDisabled }: Props)
name: `permissions.secrets.${position}.conditions` name: `permissions.secrets.${position}.conditions`
}); });
const conditionErrorMessage =
errors?.permissions?.secrets?.[position]?.conditions?.message ||
errors?.permissions?.secrets?.[position]?.conditions?.root?.message;
return ( return (
<div className="mt-6 border-t border-t-mineshaft-600 bg-mineshaft-800 pt-2"> <div className="mt-6 border-t border-t-mineshaft-600 bg-mineshaft-800 pt-2">
<p className="mt-2 text-gray-300">Conditions</p> <p className="mt-2 text-gray-300">Conditions</p>
@@ -147,10 +151,10 @@ export const SecretPermissionConditions = ({ position = 0, isDisabled }: Props)
); );
})} })}
</div> </div>
{errors?.permissions?.secrets?.[position]?.conditions?.message && ( {conditionErrorMessage && (
<div className="flex items-center space-x-2 py-2 text-sm text-gray-400"> <div className="flex items-center space-x-2 py-2 text-sm text-gray-400">
<FontAwesomeIcon icon={faWarning} className="text-red" /> <FontAwesomeIcon icon={faWarning} className="text-red" />
<span>{errors?.permissions?.secrets?.[position]?.conditions?.message}</span> <span>{conditionErrorMessage}</span>
</div> </div>
)} )}
<div> <div>