mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-25 10:12:35 +00:00
Enforce absolute paths for sudo commands
This commit is contained in:
@@ -46,6 +46,20 @@ function toSshSudoMode(value: string | null | undefined): SshSudoMode {
|
|||||||
return "none";
|
return "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasOnlyAbsoluteSudoCommands(value: string | undefined): boolean {
|
||||||
|
if (!value?.trim()) return true;
|
||||||
|
|
||||||
|
const commands = value
|
||||||
|
.split(",")
|
||||||
|
.map((command) => command.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
return commands.every((command) => {
|
||||||
|
const executable = command.split(/\s+/)[0];
|
||||||
|
return executable.startsWith("/");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export type RoleFormValues = {
|
export type RoleFormValues = {
|
||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
@@ -74,19 +88,33 @@ export function RoleForm({
|
|||||||
const { isPaidUser } = usePaidStatus();
|
const { isPaidUser } = usePaidStatus();
|
||||||
const { env } = useEnvContext();
|
const { env } = useEnvContext();
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z
|
||||||
name: z
|
.object({
|
||||||
.string({ message: t("nameRequired") })
|
name: z
|
||||||
.min(1)
|
.string({ message: t("nameRequired") })
|
||||||
.max(32),
|
.min(1)
|
||||||
description: z.string().max(255).optional(),
|
.max(32),
|
||||||
requireDeviceApproval: z.boolean().optional(),
|
description: z.string().max(255).optional(),
|
||||||
allowSsh: z.boolean().optional(),
|
requireDeviceApproval: z.boolean().optional(),
|
||||||
sshSudoMode: z.enum(SSH_SUDO_MODE_VALUES),
|
allowSsh: z.boolean().optional(),
|
||||||
sshSudoCommands: z.string().optional(),
|
sshSudoMode: z.enum(SSH_SUDO_MODE_VALUES),
|
||||||
sshCreateHomeDir: z.boolean().optional(),
|
sshSudoCommands: z.string().optional(),
|
||||||
sshUnixGroups: z.string().optional()
|
sshCreateHomeDir: z.boolean().optional(),
|
||||||
});
|
sshUnixGroups: z.string().optional()
|
||||||
|
})
|
||||||
|
.superRefine((values, ctx) => {
|
||||||
|
if (
|
||||||
|
values.sshSudoMode === "commands" &&
|
||||||
|
!hasOnlyAbsoluteSudoCommands(values.sshSudoCommands)
|
||||||
|
) {
|
||||||
|
ctx.addIssue({
|
||||||
|
code: z.ZodIssueCode.custom,
|
||||||
|
path: ["sshSudoCommands"],
|
||||||
|
message:
|
||||||
|
"Each sudo command must start with an absolute path (for example, /usr/bin/systemctl)."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const defaultValues: RoleFormValues = role
|
const defaultValues: RoleFormValues = role
|
||||||
? {
|
? {
|
||||||
@@ -296,7 +324,9 @@ export function RoleForm({
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name="allowSsh"
|
name="allowSsh"
|
||||||
render={({ field }) => {
|
render={({ field }) => {
|
||||||
const allowSshOptions: OptionSelectOption<"allow" | "disallow">[] = [
|
const allowSshOptions: OptionSelectOption<
|
||||||
|
"allow" | "disallow"
|
||||||
|
>[] = [
|
||||||
{
|
{
|
||||||
value: "allow",
|
value: "allow",
|
||||||
label: t("roleAllowSshAllow")
|
label: t("roleAllowSshAllow")
|
||||||
@@ -311,7 +341,9 @@ export function RoleForm({
|
|||||||
<FormLabel>
|
<FormLabel>
|
||||||
{t("roleAllowSsh")}
|
{t("roleAllowSsh")}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<OptionSelect<"allow" | "disallow">
|
<OptionSelect<
|
||||||
|
"allow" | "disallow"
|
||||||
|
>
|
||||||
options={allowSshOptions}
|
options={allowSshOptions}
|
||||||
value={
|
value={
|
||||||
sshDisabled
|
sshDisabled
|
||||||
@@ -322,7 +354,9 @@ export function RoleForm({
|
|||||||
}
|
}
|
||||||
onChange={(v) => {
|
onChange={(v) => {
|
||||||
if (sshDisabled) return;
|
if (sshDisabled) return;
|
||||||
field.onChange(v === "allow");
|
field.onChange(
|
||||||
|
v === "allow"
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
cols={2}
|
cols={2}
|
||||||
disabled={sshDisabled}
|
disabled={sshDisabled}
|
||||||
|
|||||||
Reference in New Issue
Block a user