allow edit admin role ssh and support null authDaemonMode

This commit is contained in:
miloschwartz
2026-02-20 20:25:14 -08:00
parent d6ba34aeea
commit 3f2bdf081f
8 changed files with 38 additions and 21 deletions

View File

@@ -685,7 +685,7 @@ export const roles = sqliteTable("roles", {
sshSudoMode: text("sshSudoMode").default("none"), // "none" | "full" | "commands" sshSudoMode: text("sshSudoMode").default("none"), // "none" | "full" | "commands"
sshSudoCommands: text("sshSudoCommands").default("[]"), sshSudoCommands: text("sshSudoCommands").default("[]"),
sshCreateHomeDir: integer("sshCreateHomeDir", { mode: "boolean" }).default( sshCreateHomeDir: integer("sshCreateHomeDir", { mode: "boolean" }).default(
false true
), ),
sshUnixGroups: text("sshUnixGroups").default("[]") sshUnixGroups: text("sshUnixGroups").default("[]")
}); });

View File

@@ -272,7 +272,8 @@ export async function createOrg(
orgId: newOrg[0].orgId, orgId: newOrg[0].orgId,
isAdmin: true, isAdmin: true,
name: "Admin", name: "Admin",
description: "Admin role with the most permissions" description: "Admin role with the most permissions",
sshSudoMode: "full"
}) })
.returning({ roleId: roles.roleId }); .returning({ roleId: roles.roleId });

View File

@@ -102,16 +102,14 @@ export async function updateRole(
); );
} }
if (role[0].isAdmin) { const orgId = role[0].orgId;
return next( const isAdminRole = role[0].isAdmin;
createHttpError(
HttpCode.FORBIDDEN, if (isAdminRole) {
`Cannot update a Admin role` delete updateData.name;
) delete updateData.description;
);
} }
const orgId = role[0].orgId;
if (!orgId) { if (!orgId) {
return next( return next(
createHttpError( createHttpError(

View File

@@ -84,7 +84,7 @@ const CredenzaContent = ({ className, children, ...props }: CredenzaProps) => {
return ( return (
<CredenzaContent <CredenzaContent
className={cn( className={cn(
"overflow-y-auto max-h-[100dvh] md:max-h-screen md:top-[200px] md:translate-y-0", "overflow-y-auto max-h-[100dvh] md:max-h-screen md:top-[clamp(1.5rem,12vh,200px)] md:translate-y-0",
className className
)} )}
{...props} {...props}

View File

@@ -46,11 +46,13 @@ export default function EditRoleForm({
async function onSubmit(values: RoleFormValues) { async function onSubmit(values: RoleFormValues) {
const payload: UpdateRoleBody = { const payload: UpdateRoleBody = {
name: values.name,
description: values.description || undefined,
requireDeviceApproval: values.requireDeviceApproval, requireDeviceApproval: values.requireDeviceApproval,
allowSsh: values.allowSsh allowSsh: values.allowSsh
}; };
if (!role.isAdmin) {
payload.name = values.name;
payload.description = values.description || undefined;
}
if (isPaidUser(tierMatrix.sshPam)) { if (isPaidUser(tierMatrix.sshPam)) {
payload.sshSudoMode = values.sshSudoMode; payload.sshSudoMode = values.sshSudoMode;
payload.sshCreateHomeDir = values.sshCreateHomeDir; payload.sshCreateHomeDir = values.sshCreateHomeDir;

View File

@@ -385,7 +385,7 @@ export function InternalResourceForm({
tcpPortRangeString: resource.tcpPortRangeString ?? "*", tcpPortRangeString: resource.tcpPortRangeString ?? "*",
udpPortRangeString: resource.udpPortRangeString ?? "*", udpPortRangeString: resource.udpPortRangeString ?? "*",
disableIcmp: resource.disableIcmp ?? false, disableIcmp: resource.disableIcmp ?? false,
authDaemonMode: resource.authDaemonMode ?? null, authDaemonMode: resource.authDaemonMode ?? "site",
authDaemonPort: resource.authDaemonPort ?? null, authDaemonPort: resource.authDaemonPort ?? null,
roles: [], roles: [],
users: [], users: [],
@@ -413,7 +413,7 @@ export function InternalResourceForm({
}); });
const mode = form.watch("mode"); const mode = form.watch("mode");
const authDaemonMode = form.watch("authDaemonMode"); const authDaemonMode = form.watch("authDaemonMode") ?? "site";
const hasInitialized = useRef(false); const hasInitialized = useRef(false);
const previousResourceId = useRef<number | null>(null); const previousResourceId = useRef<number | null>(null);
@@ -466,7 +466,7 @@ export function InternalResourceForm({
tcpPortRangeString: resource.tcpPortRangeString ?? "*", tcpPortRangeString: resource.tcpPortRangeString ?? "*",
udpPortRangeString: resource.udpPortRangeString ?? "*", udpPortRangeString: resource.udpPortRangeString ?? "*",
disableIcmp: resource.disableIcmp ?? false, disableIcmp: resource.disableIcmp ?? false,
authDaemonMode: resource.authDaemonMode ?? null, authDaemonMode: resource.authDaemonMode ?? "site",
authDaemonPort: resource.authDaemonPort ?? null, authDaemonPort: resource.authDaemonPort ?? null,
roles: [], roles: [],
users: [], users: [],

View File

@@ -138,6 +138,7 @@ export function RoleForm({
const sshDisabled = !isPaidUser(tierMatrix.sshPam); const sshDisabled = !isPaidUser(tierMatrix.sshPam);
const sshSudoMode = form.watch("sshSudoMode"); const sshSudoMode = form.watch("sshSudoMode");
const isAdminRole = variant === "edit" && role?.isAdmin === true;
useEffect(() => { useEffect(() => {
if (sshDisabled) { if (sshDisabled) {
@@ -161,7 +162,11 @@ export function RoleForm({
<FormItem> <FormItem>
<FormLabel>{t("accessRoleName")}</FormLabel> <FormLabel>{t("accessRoleName")}</FormLabel>
<FormControl> <FormControl>
<Input {...field} /> <Input
{...field}
disabled={isAdminRole}
readOnly={isAdminRole}
/>
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -174,7 +179,11 @@ export function RoleForm({
<FormItem> <FormItem>
<FormLabel>{t("description")}</FormLabel> <FormLabel>{t("description")}</FormLabel>
<FormControl> <FormControl>
<Input {...field} /> <Input
{...field}
disabled={isAdminRole}
readOnly={isAdminRole}
/>
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -203,7 +212,11 @@ export function RoleForm({
{t("accessRoleName")} {t("accessRoleName")}
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input {...field} /> <Input
{...field}
disabled={isAdminRole}
readOnly={isAdminRole}
/>
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -218,7 +231,11 @@ export function RoleForm({
{t("description")} {t("description")}
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input {...field} /> <Input
{...field}
disabled={isAdminRole}
readOnly={isAdminRole}
/>
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>

View File

@@ -135,7 +135,6 @@ export default function UsersTable({ roles }: RolesTableProps) {
</DropdownMenu> </DropdownMenu>
<Button <Button
variant={"outline"} variant={"outline"}
disabled={isAdmin || false}
onClick={() => { onClick={() => {
setEditingRole(roleRow); setEditingRole(roleRow);
setIsEditDialogOpen(true); setIsEditDialogOpen(true);