remove the dead multi-user surface
Officer is single-user: the server owner is the only account, created once by /auth/bootstrap. Everything that existed to serve additional users was unreachable, so it is gone rather than left looking like it does something. Accounts: drop the invite / resend-invite / delete / list-users routes and the Users settings screen, the inert /auth/signup handler, and the account verification chain it fed (verify, resend-verification, VerifyScreen, the UserInvite + VerifyAdmin + VerifyRegistration templates). /auth/verify-token survives for password resets only, and now requires a reset-password token rather than accepting any signed JWT. Roles: drop the users.role column and the four-value USER_ROLES enum. The permissions table granted every role identical methods, and every role === 'Super Admin' check was permanently true. The JWT no longer carries a role claim. Sandbox: remove sidecar/sandbox.ts and its five call sites. bwrap was selected only for non-Super-Admin users, so it never ran. It was also not a usable agent jail as written — --share-net, the project root (with .env) bound read-only, and runuser dropping to the server's own uid. Rebuilding it for agent containment would be a different construction, and git history keeps this one. getHomeDir keeps its DATA_PATH meaning; the new getOwnerHomeDir resolves the owner's real login home, which is what terminals, chats and task runs use. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
92de996412
commit
044aacf4d5
@@ -7,7 +7,6 @@ export type DockItem = {
|
||||
to: string;
|
||||
icon: LucideIcon;
|
||||
color: string;
|
||||
role?: string;
|
||||
};
|
||||
|
||||
type DockProps = {
|
||||
@@ -109,8 +108,21 @@ export const Dock = ({ items, className }: DockProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
import { Home, MessageCircle, FileText, FolderOpen, Code, LayoutGrid, ScrollText, FolderKanban, Monitor, Mail, Globe, MonitorSmartphone, Workflow } from 'lucide-react';
|
||||
import {
|
||||
Home,
|
||||
MessageCircle,
|
||||
FileText,
|
||||
FolderOpen,
|
||||
Code,
|
||||
LayoutGrid,
|
||||
ScrollText,
|
||||
FolderKanban,
|
||||
Monitor,
|
||||
Mail,
|
||||
Globe,
|
||||
MonitorSmartphone,
|
||||
Workflow,
|
||||
} from 'lucide-react';
|
||||
|
||||
export const ALL_DOCK_ITEMS: DockItem[] = [
|
||||
{ label: 'Home', to: '/', icon: Home, color: '#f59e0b' },
|
||||
@@ -124,7 +136,7 @@ export const ALL_DOCK_ITEMS: DockItem[] = [
|
||||
{ label: 'Terminal', to: '/terminal', icon: Monitor, color: '#f97316' },
|
||||
{ label: 'Projects', to: '/projects', icon: FolderKanban, color: '#10b981' },
|
||||
{ label: 'Browser', to: '/browser', icon: Globe, color: '#06b6d4' },
|
||||
{ label: 'Desktop', to: '/desktop', icon: MonitorSmartphone, color: '#ec4899', role: 'Super Admin' },
|
||||
{ label: 'Desktop', to: '/desktop', icon: MonitorSmartphone, color: '#ec4899' },
|
||||
{ label: 'Dashboards', to: '/dashboards', icon: LayoutGrid, color: '#8b5cf6' },
|
||||
];
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Link } from 'react-router';
|
||||
import * as Dropdown from '@/components/ui/dropdown-menu';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { User, Users, LogOut, Settings, Package, Puzzle, Rocket, Sun, Moon, Bot } from 'lucide-react';
|
||||
import { User, LogOut, Settings, Package, Puzzle, Rocket, Sun, Moon, Bot } from 'lucide-react';
|
||||
import { useAuth } from 'hooks/useAuth';
|
||||
import { useTranslation } from '@/lib/i18n';
|
||||
import { useColorMode } from '@/components/ui/ThemeProvider';
|
||||
@@ -16,8 +16,6 @@ export function UserMenu() {
|
||||
const { settings, saveSettings } = useSettings();
|
||||
if (isLoading) return null;
|
||||
|
||||
const isAdmin = user?.role !== 'Member';
|
||||
|
||||
const toggleColorMode = () => {
|
||||
const next = colorMode === 'dark' ? 'light' : 'dark';
|
||||
setColorMode(next);
|
||||
@@ -43,22 +41,18 @@ export function UserMenu() {
|
||||
{t('header.userMenu.profile')}
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
{isAdmin && (
|
||||
<>
|
||||
<DropdownMenuItem asChild className="cursor-pointer">
|
||||
<Link to="/settings/system">
|
||||
<Settings className="mr-2 h-4 w-4" />
|
||||
{t('header.userMenu.systemSettings')}
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild className="cursor-pointer">
|
||||
<Link to="/settings/resources">
|
||||
<Package className="mr-2 h-4 w-4" />
|
||||
{t('header.userMenu.resources')}
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
</>
|
||||
)}
|
||||
<DropdownMenuItem asChild className="cursor-pointer">
|
||||
<Link to="/settings/system">
|
||||
<Settings className="mr-2 h-4 w-4" />
|
||||
{t('header.userMenu.systemSettings')}
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild className="cursor-pointer">
|
||||
<Link to="/settings/resources">
|
||||
<Package className="mr-2 h-4 w-4" />
|
||||
{t('header.userMenu.resources')}
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild className="cursor-pointer">
|
||||
<Link to="/settings/ai">
|
||||
<Bot className="mr-2 h-4 w-4" />
|
||||
@@ -77,14 +71,6 @@ export function UserMenu() {
|
||||
Apps
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
{user?.role === 'Super Admin' && (
|
||||
<DropdownMenuItem asChild className="cursor-pointer">
|
||||
<Link to="/settings/users">
|
||||
<Users className="mr-2 h-4 w-4" />
|
||||
Users
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={toggleColorMode} className="cursor-pointer">
|
||||
{colorMode === 'dark' ? <Sun className="mr-2 h-4 w-4" /> : <Moon className="mr-2 h-4 w-4" />}
|
||||
|
||||
Reference in New Issue
Block a user