Enforce absolute paths for sudo commands

This commit is contained in:
Owen
2026-05-21 12:14:52 -07:00
parent af13790c93
commit e4e8b33e9f

View File

@@ -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}