Conversation
Replace raw WebSocket handling with Socket.IO/Engine.IO protocol support in agent/internal/ws: build Socket.IO URL, perform Engine.IO OPEN handshake, connect to namespace, emit/parse Socket.IO events for auth, adapt read/write loops, add ping loop and reconnection handling, and map events to protocol messages. Update agent registration endpoint to /api/v1/servers/register. Add config file handling in cmd/agent (respect --config flag, set key file relative to config path) and import filepath. Update install scripts to new download API paths for Windows and *nix. Adjust frontend servers page copy to show registration tokens expire in 24 hours. Also add a Contributors section to the create-pr skill guidance.
Add backup dirs in Dockerfiles and adjust ownership. Change server routes to use a dynamic tab param and update components to support tabbed ServerDetail pages. Improve metrics handling by adding serverId support, more resilient field parsing, and server-specific metrics API calls. Revamp ServerDetail: introduce token modal and AgentRegistrationSection, reorganize Metrics, Settings and Security areas (IP allowlist, API key rotation, security alerts), move delete/generate token flows and wire up navigation. Update Servers and Docker pages to handle different API response shapes (Array checks) and tweak install modal copy/UX. Rename backend API call for registration token to /regenerate-token. Add many UI/Icon/CSS adjustments to support the new layouts and interactions, and fix various small bugs and data-shape assumptions.
Backend: add PUT /cron/jobs/<id> endpoint and CronService.update_job to update job metadata and (on Linux) modify the system crontab; includes schedule validation and error handling. Frontend: add useTabParam hook and update routes/PageTitle logic to support optional :tab URL segments for many pages, enabling deep-linked tabs. Update CronJobs UI to unify create/edit modal, add edit-on-click, run-output modal, improved SVG icon attributes, and wire updateCronJob in the API client. Styles: global SVG button rules, hover for cron items, and run-output styles.
Backend: filter out virtual/pseudo filesystem types and skip noisy mount prefixes (e.g. /snap/, /var/lib/docker/, /run/), and deduplicate mounts by device so only a single mount per device is reported for disk usage. Frontend: make the file manager sidebar scrollable with a max-height (calc(100vh - 120px)), disable that height in the small-screen modal, and remove max-height restriction for the last child to prevent clipping.
Backend: Replace direct sudo/subprocess.run calls with run_privileged and privileged_cmd, add _needs_sudo/privileged_cmd logic and is_command_available checks, and return clearer errors for missing binaries (journalctl/grep/tail/truncate/logrotate/systemctl/service). Add FileNotFoundError handling and use privileged_cmd for Popen. Frontend: UI and style refinements across Downloads, Security and Terminal pages — simplified Linux icon, added release date and banner actions, redesigned scanner UI into interactive scan cards with custom path and toolbar, handle unavailable journalctl with an empty state, update SVG icons. Styles (.less): switch mono font to JetBrains Mono, adjust spacing/gaps, sidebar text truncation, revamp downloads and security card styles, and improve terminal log fonts, wrapping and processes table layout.
Introduce safer system interactions and improved logging fallbacks across services. Replace direct sudo/subprocess calls with run_privileged/privileged_cmd, add command availability checks (is_command_available) and Linux guards for user management. Enhance LogService with fallback readers (python file I/O, grep fallback, syslog and Windows Event Log support) and standardize responses via sourced_result. Update frontend Terminal to display log source and adjust UI when journalctl is unavailable. Misc: delegate ProcessService log retrieval to LogService, add PackageManager usage in PHP/SSL installs, and add warning logging in DeploymentService when diff generation fails.
Introduce a full email management feature: adds EmailService (Postfix/Dovecot/SpamAssassin/OpenDKIM management, account creation, forwarding, webmail, queue/logs, service control), new email API blueprint with admin-protected endpoints, and EmailAccount DB model. Register the email blueprint in app init. Frontend: add Email page, route and sidebar link, preload accent color + theme to prevent FOUC, new email styles and a dashboard layout hook. Also update ROADMAP.md to include Phase 21 SSO/OAuth and bump roadmap last-updated date.
Add full SSO (Google, GitHub, generic OIDC, SAML) support and integrate Alembic-based DB migrations. Introduces OAuthIdentity model, sso_service, SSO API blueprint (authorize/callback/link/unlink/admin/config/test), and settings to enable/configure providers and enforce SSO-only logins. Integrates Flask-Migrate and a MigrationService with API endpoints for status/backup/apply/history and includes Alembic scaffolding (migrations/versions/001_baseline.py). Update app init to register SSO and migrations blueprints and initialize Migrate; replace fragile auto-column hack with MigrationService.prepare/check. Update User model (nullable password_hash, auth_provider, has_password/to_dict fields), add AuditLog SSO actions, add frontend SSO components/pages and a migration UI, and update ROADMAP and requirements. Notes: token encryption uses Fernet derived from SECRET_KEY; migrations may add the new auth_provider column at startup.
Introduce programmatic API features and observability: add API Key management, API usage analytics, webhook event subscriptions, and OpenAPI docs. New models (ApiKey, ApiUsageLog, ApiUsageSummary, EventSubscription, EventDelivery), services (api_analytics, api_key, event, openapi), and blueprints (/api-keys, /api-analytics, /event-subscriptions, /docs) were added and registered in create_app. Middleware for API key authentication, buffered analytics logging (with a flush thread), and enhanced rate limiting (custom key function and response headers) were implemented; RBAC was updated to accept API key auth via an auth_required decorator. Background threads for hourly aggregation and event retry were added; security CSP updated to allow resources for Swagger UI. Frontend settings UI and styles were added/updated for API keys and webhooks, and requirements were updated.
Introduce team invitation support and a revamped email subsystem plus admin features. Adds Invitation model and API endpoints (create, list, revoke, resend, validate) and integrates invitation validation into user registration. Replaces old email account model with richer email models (EmailDomain, EmailAccount, EmailAlias, EmailForwardingRule, DNSProviderConfig) and updates models __init__. Refactors email API to manage domains, accounts, aliases, forwarding, DNS providers, spamassassin, Roundcube/Postfix services and queue/log endpoints. Adds several backend services (invitation, DNS provider, DKIM, Dovecot, Postfix, Roundcube, SpamAssassin, permission service) and a DB migration for permissions/invitations. Enhances admin API with permission management and activity dashboard endpoints, extends audit log actions, and adds a permission_required RBAC decorator. Includes frontend additions for settings/invitations UI and miscellaneous config/service updates and tests.
Bump current development version to v1.5.0 and reorganize the roadmap to reflect completed work, reprioritize upcoming work, and add several new planned phases. Marked many items as completed (Team & Permissions, API Enhancements, SSO/OAuth, Database Migrations/Alembic, Multi-Server, Git Deployment, Advanced Security) and replaced older phase entries with new high-priority initiatives such as the New UI & Services page, Customizable Sidebar & Dashboard Views, Migration Wizard frontend, Container Logs & Monitoring UI, DNS management, Nginx advanced config, and expanded planned phases through v3.0. Also updated the version table to show completed and current releases and adjusted the contribution priority list to highlight UI, DNS, status page, and Nginx work. These changes keep the roadmap accurate with recent progress and surface critical next steps (notably merging the new-ui branch and migration UX).
Add a nosec comment to the http_requests.post call in EventService to suppress Bandit B113 warnings for the subscription post. Update many tests in test_utils_system.py to explicitly patch app.utils.system.os.name as 'posix' and app.utils.system.shutil.which to simulate presence of /usr/bin/sudo (and include sudo in apt/dnf side effects). Adjust test function signatures to accept the new mock and ensure package/service tests run as a non-root POSIX environment with sudo available.
Update backend/requirements.txt to upgrade Authlib from 1.5.2 to 1.6.9. Verify SSO/OAuth flows and run tests to ensure compatibility with the newer Authlib release.
There was a problem hiding this comment.
Pull request overview
This PR introduces major platform features (email server management, SSO/OAuth login, API keys + analytics + webhooks, invitations/RBAC, Alembic migrations) and includes broad UI/UX and styling updates, plus agent installer endpoint updates.
Changes:
- Adds SSO + invitation-based registration flows, feature permissions, and migration gating in the app/router.
- Introduces API key auth, rate limiting/analytics scaffolding, and webhook subscription UI components.
- Updates theming (runtime accent + white-label branding), tabbed routing via URL params, and assorted UI polish/styles.
Reviewed changes
Copilot reviewed 147 out of 161 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/styles/pages/_cron.less | Adds hover/click affordances and run-output styling for cron UI. |
| frontend/src/styles/pages/_backups.less | Updates accent color usage to raw variant for LESS color functions. |
| frontend/src/styles/pages/_auth.less | Adds SSO button styling and loading spinner animation. |
| frontend/src/styles/pages/_applications.less | Updates accent border color to raw variant for LESS color functions. |
| frontend/src/styles/main.less | Imports new API/email/migration wizard styles. |
| frontend/src/styles/layout/_sidebar.less | Adds white-label brand section styles and truncation for nav labels. |
| frontend/src/styles/components/_uptime.less | Updates accent gradient to raw variant for LESS color functions. |
| frontend/src/styles/components/_two-factor.less | Updates accent fades to raw variant for LESS color functions. |
| frontend/src/styles/components/_toasts.less | Updates accent backgrounds/borders to raw variant for LESS color functions. |
| frontend/src/styles/components/_tabs.less | Adjusts tab spacing. |
| frontend/src/styles/components/_spinner.less | Updates spinner border fade to raw variant. |
| frontend/src/styles/components/_query-runner.less | Updates accent fades/borders to raw variant for LESS color functions. |
| frontend/src/styles/components/_notifications.less | Updates accent borders/backgrounds to raw variant for LESS color functions. |
| frontend/src/styles/components/_modals.less | Updates accent background fade to raw variant. |
| frontend/src/styles/components/_linked-apps.less | Updates accent fades/borders to raw variant for LESS color functions. |
| frontend/src/styles/components/_env-vars.less | Updates accent background fade to raw variant for LESS color functions. |
| frontend/src/styles/components/_cards.less | Updates accent background fade to raw variant for LESS color functions. |
| frontend/src/styles/components/_build.less | Updates accent gradient fade to raw variant for LESS color functions. |
| frontend/src/styles/components/_badges.less | Updates accent backgrounds/borders to raw variant for LESS color functions. |
| frontend/src/styles/_variables.less | Splits accent tokens into raw compile-time values + runtime CSS vars; updates mono font stack. |
| frontend/src/styles/_theme-variables.less | Adds default CSS custom properties for accent colors. |
| frontend/src/pages/WordPressProject.jsx | Switches to URL-param tabs via useTabParam. |
| frontend/src/pages/WordPressDetail.jsx | Switches to URL-param tabs via useTabParam. |
| frontend/src/pages/Terminal.jsx | Switches to URL-param tabs; improves journal log fallback UX and SVG styling. |
| frontend/src/pages/Setup.jsx | Replaces static SVG import with reusable ServerKitLogo component. |
| frontend/src/pages/Servers.jsx | Adjusts server/group list response handling; UI copy tweaks; removes delete actions UI wiring. |
| frontend/src/pages/Security.jsx | Switches to URL-param tabs; refactors scanner UI layout and empty states. |
| frontend/src/pages/SSOCallback.jsx | Adds OAuth callback handler page. |
| frontend/src/pages/Register.jsx | Adds invitation token validation flow; disables open registration when configured off. |
| frontend/src/pages/Monitoring.jsx | Switches to URL-param tabs via useTabParam. |
| frontend/src/pages/Login.jsx | Adds SSO provider buttons + SSO-to-2FA bridging; supports password-login disable. |
| frontend/src/pages/Git.jsx | Switches to URL-param tabs via useTabParam. |
| frontend/src/pages/FTPServer.jsx | Switches to URL-param tabs via useTabParam. |
| frontend/src/pages/Docker.jsx | Switches to URL-param tabs via useTabParam; adjusts servers response handling. |
| frontend/src/pages/Databases.jsx | Switches to URL-param tabs via useTabParam; keeps “auto-default tab” only when no explicit tab route. |
| frontend/src/pages/Dashboard.jsx | Adds dashboard layout persistence hook; renders widgets from stored layout. |
| frontend/src/pages/Backups.jsx | Switches to URL-param tabs via useTabParam. |
| frontend/src/pages/ApplicationDetail.jsx | Switches to URL-param tabs via useTabParam. |
| frontend/src/hooks/useTabParam.js | New hook to sync active tab with :tab route param. |
| frontend/src/hooks/useDashboardLayout.js | New hook persisting dashboard widget visibility/order in localStorage. |
| frontend/src/contexts/ThemeContext.jsx | Adds runtime accent color + white-label settings and applies CSS vars at boot. |
| frontend/src/contexts/AuthContext.jsx | Adds setup status fields for SSO providers/password login/migrations and permission helper. |
| frontend/src/components/settings/WebhookSubscriptionModal.jsx | Adds modal UI for webhook subscription create/edit. |
| frontend/src/components/settings/UsersTab.jsx | Embeds invitations management UI in Users settings. |
| frontend/src/components/settings/UserModal.jsx | Adds per-user permission customization via PermissionEditor and templates. |
| frontend/src/components/settings/PermissionEditor.jsx | Adds UI editor for per-feature read/write permissions. |
| frontend/src/components/settings/MigrationHistoryTab.jsx | Adds settings UI to view migration history. |
| frontend/src/components/settings/InvitationsTab.jsx | Adds invitations list + actions + invite modal entry point. |
| frontend/src/components/settings/ApiKeyModal.jsx | Adds API key creation/one-time display modal. |
| frontend/src/components/Sidebar.jsx | Adds white-label brand rendering and Email nav entry; uses ServerKitLogo component. |
| frontend/src/components/ServerKitLogo.jsx | Adds reusable SVG logo component with accent gradient. |
| frontend/src/components/SSOProviderIcon.jsx | Adds provider icons (Google/GitHub + fallback). |
| frontend/src/components/MetricsGraph.jsx | Adds optional serverId to fetch per-server metrics history; supports legacy response keys. |
| frontend/src/App.jsx | Adds routes for email, migrations, SSO callback, and /:tab sub-routes; migration gating in routes/title updater. |
| frontend/index.html | Extends FOUC script to apply theme + accent CSS vars before React boot. |
| backend/tests/test_utils_system.py | Updates tests to account for sudo detection and posix behavior. |
| backend/tests/conftest.py | Adds pytest fixtures for Flask app/client/auth headers. |
| backend/requirements.txt | Adds Flask-Migrate, Authlib, python3-saml, apispec dependencies. |
| backend/migrations/versions/002_permissions_invitations.py | Alembic revision adding user.permissions and invitations table. |
| backend/migrations/script.py.mako | Adds Alembic migration template. |
| backend/migrations/env.py | Adds Alembic env with Flask-Migrate engine/metadata wiring. |
| backend/migrations/alembic.ini | Adds Alembic config stub. |
| backend/config.py | Adds TestingConfig and registers it in config map. |
| backend/cli.py | Replaces ad-hoc migration logic with Alembic-backed status/migrate/history commands. |
| backend/app/utils/system.py | Adds sudo detection helpers and a standardized sourced-result response shape. |
| backend/app/services/wordpress_service.py | Refactors privileged operations to use run_privileged/privileged_cmd and improves exception handling. |
| backend/app/services/system_service.py | Switches timezone setters to run_privileged. |
| backend/app/services/ssl_service.py | Uses PackageManager + is_command_available for certbot install and nginx checks. |
| backend/app/services/settings_service.py | Adds SSO/rate-limit settings; hardens legacy role migration with rollback. |
| backend/app/services/roundcube_service.py | Adds Docker-based Roundcube management service and nginx proxy config generator. |
| backend/app/services/process_service.py | Switches service control to run_privileged and uses LogService for logs. |
| backend/app/services/php_service.py | Switches installs to PackageManager and improves exception specificity. |
| backend/app/services/permission_service.py | Adds service for validating/updating per-user permissions. |
| backend/app/services/nginx_service.py | Adds nginx presence check before testing config. |
| backend/app/services/invitation_service.py | Adds invitation lifecycle + SMTP sending + cleanup via service layer. |
| backend/app/services/ftp_service.py | Hardens Linux-only user mgmt and uses privileged helpers for user ops. |
| backend/app/services/file_service.py | Filters virtual mounts and deduplicates disk devices for disk usage listing. |
| backend/app/services/deployment_service.py | Adds logger + warning on diff generation failure. |
| backend/app/services/cron_service.py | Changes presets response shape and adds cron job update support. |
| backend/app/services/backup_service.py | Adds command availability checks for database backup/restore tooling. |
| backend/app/services/audit_service.py | Emits webhook events for selected audit actions (best-effort). |
| backend/app/services/api_key_service.py | Adds API key CRUD/validate/rotate service. |
| backend/app/paths.py | Adds email/mail server paths/constants. |
| backend/app/models/user.py | Makes password optional; adds auth_provider and permissions with helper methods. |
| backend/app/models/oauth_identity.py | Adds model for linking external identities to users. |
| backend/app/models/invitation.py | Adds invitation persistence model with permissions support. |
| backend/app/models/event_subscription.py | Adds webhook subscription + delivery record models. |
| backend/app/models/email.py | Adds email domain/account/alias/forwarding/DNS provider models. |
| backend/app/models/audit_log.py | Adds audit action constants for new systems (SSO/API keys/invitations/permissions). |
| backend/app/models/api_usage.py | Adds API usage log + summary models. |
| backend/app/models/api_key.py | Adds API key model with hashing/scopes/tier metadata. |
| backend/app/models/init.py | Exposes new models in package exports. |
| backend/app/middleware/security.py | Adjusts CSP allowlist for Swagger UI assets on unpkg. |
| backend/app/middleware/rbac.py | Adds auth_required and permission_required; supports API key user context. |
| backend/app/middleware/rate_limit.py | Adds dynamic per-tier rate limit helpers and header registration. |
| backend/app/middleware/api_key_auth.py | Adds X-API-Key authentication middleware and usage recording. |
| backend/app/middleware/api_analytics.py | Adds buffered API request analytics logging + background flush thread. |
| backend/app/api/migrations.py | Adds migration status/backup/apply/history endpoints. |
| backend/app/api/invitations.py | Adds invitations CRUD endpoints and public validate endpoint. |
| backend/app/api/docs.py | Adds Swagger UI and OpenAPI JSON endpoints. |
| backend/app/api/cron.py | Adds PUT endpoint for updating cron jobs. |
| backend/app/api/auth.py | Adds SSO providers/password-login state to setup status; invite-based registration; blocks password login in SSO-only mode. |
| backend/app/api/api_keys.py | Adds user API key management endpoints. |
| backend/app/api/api_analytics.py | Adds admin API analytics endpoints. |
| backend/app/api/admin.py | Adds permission endpoints and activity summary/feed. |
| backend/Dockerfile | Creates/chowns backups directory in backend container image. |
| agent/scripts/install.sh | Updates agent download URL to new canonical API endpoint. |
| agent/scripts/install.ps1 | Updates agent download URL to new canonical API endpoint. |
| agent/internal/agent/registration.go | Updates agent registration endpoint path. |
| agent/cmd/agent/main.go | Saves config to selected path and ensures key file path is relative to config dir for custom config. |
| VERSION | Bumps version to 1.3.4. |
| Dockerfile | Creates/chowns backups directory in root container image. |
| .claude/skills/create-pr/SKILL.md | Updates internal PR-writing skill guidance (Contributors section). |
| .claude/skills/audit-less/SKILL.md | Adds internal LESS auditing skill documentation. |
Comments suppressed due to low confidence (1)
backend/app/services/cron_service.py:1
get_presets()changes the response shape from a list of preset objects (includingdescription) to a raw dict. This is an API breaking change and also drops computed descriptions. Consider restoring the previous list shape, or returning both (e.g.,presets_raw+presets) to keep backward compatibility.
"""
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| try: | ||
| cmd = ['sudo', '-u', user, cls.WP_CLI_PATH, '--path=' + path] + command | ||
| cmd = privileged_cmd(['sudo', '-u', user, cls.WP_CLI_PATH, '--path=' + path] + command) |
There was a problem hiding this comment.
privileged_cmd() is being called on a command that already hardcodes sudo. When running as root (or environments without sudo), this can still attempt to execute sudo and fail or behave unexpectedly. Build the command without sudo and let privileged_cmd() decide whether to prepend it, or update privileged_cmd() to strip a leading sudo when _needs_sudo() is false.
| cmd = privileged_cmd(['sudo', '-u', user, cls.WP_CLI_PATH, '--path=' + path] + command) | |
| cmd = privileged_cmd([cls.WP_CLI_PATH, '--path=' + path] + command) |
| api_key.record_usage(ip_address) | ||
|
|
||
| from app import db | ||
| db.session.commit() |
There was a problem hiding this comment.
Committing the SQLAlchemy session inside before_request can break request-level atomicity (it may commit unrelated pending work later in the request) and increases contention/latency by doing a commit per API request. Prefer deferring the commit to an after_request handler, or record usage in-memory and batch-flush (similar to api_analytics.py), or at least db.session.flush() and let the normal request lifecycle commit/rollback.
| db.session.commit() | |
| db.session.flush() |
| @api_analytics_bp.route('/keys/<int:key_id>/usage', methods=['GET']) | ||
| @admin_required | ||
| def key_usage(key_id): |
There was a problem hiding this comment.
key_usage is decorated with @admin_required, but the function body claims to allow key owners to view their own usage. As written, non-admin owners will never reach this logic. Replace @admin_required with an auth decorator that allows any authenticated user (e.g., @auth_required()), then enforce the admin/owner check in the function body.
| """Get usage stats for a specific API key.""" | ||
| period = request.args.get('period', '24h') | ||
|
|
||
| # Allow key owners to view their own usage |
There was a problem hiding this comment.
key_usage is decorated with @admin_required, but the function body claims to allow key owners to view their own usage. As written, non-admin owners will never reach this logic. Replace @admin_required with an auth decorator that allows any authenticated user (e.g., @auth_required()), then enforce the admin/owner check in the function body.
backend/tests/conftest.py
Outdated
| _backend = os.path.dirname(os.path.abspath(__file__)) | ||
| if _backend not in sys.path: | ||
| sys.path.insert(0, _backend) |
There was a problem hiding this comment.
The comment says 'Ensure backend root is on path', but this inserts backend/tests/ into sys.path. That can break imports like from app import create_app when tests are executed from a different working directory. Update this to insert the backend root (typically os.path.dirname(_backend)) or use an explicit Path(__file__).resolve().parents[1]-style approach.
| _backend = os.path.dirname(os.path.abspath(__file__)) | |
| if _backend not in sys.path: | |
| sys.path.insert(0, _backend) | |
| _backend_tests = os.path.dirname(os.path.abspath(__file__)) | |
| _backend_root = os.path.dirname(_backend_tests) | |
| if _backend_root not in sys.path: | |
| sys.path.insert(0, _backend_root) |
| * @param {string} defaultTab - Fallback tab when URL param is missing/invalid | ||
| * @returns {[string, (tab: string) => void]} - [activeTab, setActiveTab] | ||
| */ | ||
| export default function useTabParam(basePath, validTabs, defaultTab = validTabs[0]) { |
There was a problem hiding this comment.
The docstring says this 'syncs the active tab with a URL parameter', but when :tab is missing/invalid the hook only falls back in-memory and does not update the URL. If true sync is desired, consider navigating to defaultTab when tab is absent/invalid (and also consider whether { replace: true } is appropriate—replacing can make Back-button navigation between tabs impossible).
| const activeTab = validTabs.includes(tab) ? tab : defaultTab; | ||
| const setActiveTab = (t) => navigate(`${basePath}/${t}`, { replace: true }); |
There was a problem hiding this comment.
The docstring says this 'syncs the active tab with a URL parameter', but when :tab is missing/invalid the hook only falls back in-memory and does not update the URL. If true sync is desired, consider navigating to defaultTab when tab is absent/invalid (and also consider whether { replace: true } is appropriate—replacing can make Back-button navigation between tabs impossible).
backend/app/utils/system.py
Outdated
| return True | ||
|
|
||
|
|
||
| def privileged_cmd(cmd: Union[List[str], str]) -> Union[List[str], str]: |
There was a problem hiding this comment.
There are existing unit tests around privileged execution, but the new privileged_cmd() behavior (especially how it should behave when callers pass an already-sudo-prefixed command, and when _needs_sudo() is false) isn’t covered here. Add targeted tests for privileged_cmd() across root/non-root and posix/windows scenarios to prevent regressions like always emitting sudo.
| if isinstance(cmd, str): | ||
| if _needs_sudo() and not cmd.lstrip().startswith('sudo '): |
There was a problem hiding this comment.
There are existing unit tests around privileged execution, but the new privileged_cmd() behavior (especially how it should behave when callers pass an already-sudo-prefixed command, and when _needs_sudo() is false) isn’t covered here. Add targeted tests for privileged_cmd() across root/non-root and posix/windows scenarios to prevent regressions like always emitting sudo.
| if _needs_sudo() and cmd[0] != 'sudo': | ||
| return ['sudo'] + cmd |
There was a problem hiding this comment.
There are existing unit tests around privileged execution, but the new privileged_cmd() behavior (especially how it should behave when callers pass an already-sudo-prefixed command, and when _needs_sudo() is false) isn’t covered here. Add targeted tests for privileged_cmd() across root/non-root and posix/windows scenarios to prevent regressions like always emitting sudo.
Allow authenticated (non-admin) users to fetch API key usage by replacing @admin_required with @auth_required in api_analytics.py and importing auth_required. Add optional user support to privileged_cmd and run_privileged in app/utils/system.py so callers can run commands as a specific user (sudo -u). Update wordpress_service to use the new user keyword when invoking privileged commands. Fix tests/conftest.py to put the backend root (parent directory) on sys.path so tests import correctly.
ServerKit grew a whole new nervous system while nobody was looking. This release wires in a full email server stack, SSO/OAuth login, a developer-facing API platform with keys and webhooks, an invitation system, and rewrites the agent's transport layer from raw WebSocket to Socket.IO — plus a pile of UI polish across nearly every page.
Contributors
Highlights
/api/v1/servers/endpointsTechnical changes
Email server backend
EmailDomain,EmailMailbox,EmailAlias,EmailForwardingRuleinbackend/app/models/email.py; removed single-tableemail_account.pyemail_service.pyrefactored into focused services:postfix_service.py,dovecot_service.py,dkim_service.py,spamassassin_service.py,roundcube_service.py,dns_provider_service.pybackend/app/api/email.pywith full CRUD routes for domains, mailboxes, aliases, and forwardingEmail.jsxrewritten as a tabbed multi-panel UI with domain/mailbox/alias/forwarding/webmail viewsSSO/OAuth
backend/app/services/sso_service.py— OAuth2 flow for GitHub, GitLab, Google, Bitbucket with token exchange and user linkingbackend/app/models/oauth_identity.py— stores provider identities linked to usersbackend/app/api/sso.py— initiate/callback/unlink endpointsSSOCallback.jsxhandles OAuth redirects;SSOConfigTab.jsxin Settings for provider management;Login.jsxgains SSO buttonsAPI platform
backend/app/models/api_key.pyandapi_usage.py— API key model with SHA-256 hashing and usage loggingbackend/app/middleware/api_key_auth.py—@api_key_requireddecorator for key-authenticated routesbackend/app/middleware/rate_limit.py— token-bucket rate limiter per API keybackend/app/middleware/api_analytics.py— request/response logging middlewarebackend/app/services/api_key_service.py,api_analytics_service.py— key lifecycle and analytics aggregationbackend/app/models/event_subscription.pyandbackend/app/services/event_service.py— webhook subscriptions with HMAC-signed deliverybackend/app/api/docs.py— auto-generated OpenAPI spec viaopenapi_service.pyApiSettingsTab.jsx,ApiKeyModal.jsx,WebhookSubscriptionModal.jsxwith usage chartsInvitations and permissions
backend/app/models/invitation.pyandbackend/app/services/invitation_service.py— invite tokens with expiry, role assignment, and usage trackingbackend/app/api/invitations.py— create/list/revoke/accept endpointsbackend/app/services/permission_service.py— fine-grained permission definitions and validationbackend/app/api/admin.pyInvitationsTab.jsx,InviteModal.jsx,PermissionEditor.jsx,ActivityTab.jsx;Register.jsxsupports invite-token flowDatabase migrations
backend/migrations/withenv.py,alembic.ini, andscript.py.mako001_baseline.py— full schema baseline;002_permissions_invitations.py— permissions and invitation tablesbackend/app/services/migration_service.py— programmatic migrate/rollback/status with safety checksbackend/app/api/migrations.py— admin-only migration endpointsDatabaseMigration.jsxwizard page;MigrationHistoryTab.jsxin SettingsAgent Socket.IO migration
agent/internal/ws/client.gorewritten: Engine.IO 4 handshake (handleEngineIOOpen), Socket.IO namespace connect (connectNamespace), event-based auth flowbuildSocketIOURL,emitEvent,parseEvent,dispatchEvent,pingLoop/api/v1/agents/registerto/api/v1/servers/registerinstall.sh,install.ps1) updated to use/api/v1/servers/agent/download/URLsService hardening and fixes
log_service.py— fallback readers for journald, syslog, and direct file access when privileged commands failbackend/app/utils/system.py—run_privileged()andhas_privilege()helpers that preferpkexec/sudowith fallbackprocess_service.py,ftp_service.py,php_service.py,ssl_service.py,nginx_service.py,wordpress_service.py,backup_service.pyfile_service.py— filters virtual mounts (/proc,/sys,/snap) and deduplicates block devicesFrontend UI
ServerDetail.jsxredesigned with metric graphs, reorganized info cards, and cleaner token flowCronJobs.jsx— inline edit/create forms with expression builderTerminal.jsx— improved resize handling and style refreshSecurity.jsxandDownloads.jsx— layout and style overhauluseTabParamhook andApp.jsxroute updates for?tab=query-param routing across all tabbed pagesuseDashboardLayouthook for responsive dashboard gridThemeContextexpanded with CSS custom properties; LESS variables updated globally_api-settings.less,_email.less,_migration-wizard.less,_auth.lessMetricsGraph.jsxacceptsserverIdprop for per-server historyRBAC middleware
backend/app/middleware/rbac.pyextended withpermission_required()decorator for granular route guardingDocs and config
ROADMAP.mdandREADME.mdupdated to reflect v1.4 scope and reorganized plansVERSIONbumped to 1.3.2backend/requirements.txtaddsalembic,authlib,httpx,pyyaml,jsonschemabackend/tests/conftest.py— shared test fixtures;test_utils_system.pymockssudo/posix calls for CI