Skip to content

Add email server, SSO, API platform, and agent Socket.IO migration#29

Merged
jhd3197 merged 18 commits intomainfrom
dev
Mar 4, 2026
Merged

Add email server, SSO, API platform, and agent Socket.IO migration#29
jhd3197 merged 18 commits intomainfrom
dev

Conversation

@jhd3197
Copy link
Owner

@jhd3197 jhd3197 commented Mar 4, 2026

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

  • Full email server management: create domains, mailboxes, aliases, and forwarding rules with Postfix, Dovecot, DKIM, SpamAssassin, and Roundcube integration
  • Sign in with GitHub, GitLab, Google, or Bitbucket via SSO/OAuth, with provider configuration in Settings
  • API key management with scoped permissions, usage analytics dashboards, and webhook subscriptions for server events
  • Invite new users by email with role and permission presets
  • Database migration framework (Alembic-backed) with a visual migration wizard and rollback support
  • Cron jobs now support inline editing with a richer scheduling UI
  • Server detail page redesigned with live metrics graphs and cleaner layout
  • Agent installer scripts now use the canonical /api/v1/servers/ endpoints
Technical changes

Email server backend

  • New models: EmailDomain, EmailMailbox, EmailAlias, EmailForwardingRule in backend/app/models/email.py; removed single-table email_account.py
  • email_service.py refactored into focused services: postfix_service.py, dovecot_service.py, dkim_service.py, spamassassin_service.py, roundcube_service.py, dns_provider_service.py
  • New backend/app/api/email.py with full CRUD routes for domains, mailboxes, aliases, and forwarding
  • Frontend Email.jsx rewritten as a tabbed multi-panel UI with domain/mailbox/alias/forwarding/webmail views

SSO/OAuth

  • backend/app/services/sso_service.py — OAuth2 flow for GitHub, GitLab, Google, Bitbucket with token exchange and user linking
  • backend/app/models/oauth_identity.py — stores provider identities linked to users
  • backend/app/api/sso.py — initiate/callback/unlink endpoints
  • Frontend: SSOCallback.jsx handles OAuth redirects; SSOConfigTab.jsx in Settings for provider management; Login.jsx gains SSO buttons

API platform

  • backend/app/models/api_key.py and api_usage.py — API key model with SHA-256 hashing and usage logging
  • backend/app/middleware/api_key_auth.py@api_key_required decorator for key-authenticated routes
  • backend/app/middleware/rate_limit.py — token-bucket rate limiter per API key
  • backend/app/middleware/api_analytics.py — request/response logging middleware
  • backend/app/services/api_key_service.py, api_analytics_service.py — key lifecycle and analytics aggregation
  • backend/app/models/event_subscription.py and backend/app/services/event_service.py — webhook subscriptions with HMAC-signed delivery
  • backend/app/api/docs.py — auto-generated OpenAPI spec via openapi_service.py
  • Frontend: ApiSettingsTab.jsx, ApiKeyModal.jsx, WebhookSubscriptionModal.jsx with usage charts

Invitations and permissions

  • backend/app/models/invitation.py and backend/app/services/invitation_service.py — invite tokens with expiry, role assignment, and usage tracking
  • backend/app/api/invitations.py — create/list/revoke/accept endpoints
  • backend/app/services/permission_service.py — fine-grained permission definitions and validation
  • Admin API expanded: user permission CRUD, dashboard stats, activity feed in backend/app/api/admin.py
  • Frontend: InvitationsTab.jsx, InviteModal.jsx, PermissionEditor.jsx, ActivityTab.jsx; Register.jsx supports invite-token flow

Database migrations

  • Alembic setup in backend/migrations/ with env.py, alembic.ini, and script.py.mako
  • 001_baseline.py — full schema baseline; 002_permissions_invitations.py — permissions and invitation tables
  • backend/app/services/migration_service.py — programmatic migrate/rollback/status with safety checks
  • backend/app/api/migrations.py — admin-only migration endpoints
  • Frontend: DatabaseMigration.jsx wizard page; MigrationHistoryTab.jsx in Settings

Agent Socket.IO migration

  • agent/internal/ws/client.go rewritten: Engine.IO 4 handshake (handleEngineIOOpen), Socket.IO namespace connect (connectNamespace), event-based auth flow
  • New helpers: buildSocketIOURL, emitEvent, parseEvent, dispatchEvent, pingLoop
  • Registration endpoint changed from /api/v1/agents/register to /api/v1/servers/register
  • Install scripts (install.sh, install.ps1) updated to use /api/v1/servers/agent/download/ URLs

Service hardening and fixes

  • log_service.py — fallback readers for journald, syslog, and direct file access when privileged commands fail
  • backend/app/utils/system.pyrun_privileged() and has_privilege() helpers that prefer pkexec/sudo with fallback
  • Services updated to use privileged helpers: process_service.py, ftp_service.py, php_service.py, ssl_service.py, nginx_service.py, wordpress_service.py, backup_service.py
  • file_service.py — filters virtual mounts (/proc, /sys, /snap) and deduplicates block devices

Frontend UI

  • ServerDetail.jsx redesigned with metric graphs, reorganized info cards, and cleaner token flow
  • CronJobs.jsx — inline edit/create forms with expression builder
  • Terminal.jsx — improved resize handling and style refresh
  • Security.jsx and Downloads.jsx — layout and style overhaul
  • useTabParam hook and App.jsx route updates for ?tab= query-param routing across all tabbed pages
  • useDashboardLayout hook for responsive dashboard grid
  • ThemeContext expanded with CSS custom properties; LESS variables updated globally
  • New LESS files: _api-settings.less, _email.less, _migration-wizard.less, _auth.less
  • MetricsGraph.jsx accepts serverId prop for per-server history

RBAC middleware

  • backend/app/middleware/rbac.py extended with permission_required() decorator for granular route guarding

Docs and config

  • ROADMAP.md and README.md updated to reflect v1.4 scope and reorganized plans
  • VERSION bumped to 1.3.2
  • backend/requirements.txt adds alembic, authlib, httpx, pyyaml, jsonschema
  • backend/tests/conftest.py — shared test fixtures; test_utils_system.py mocks sudo/posix calls for CI

jhd3197 and others added 16 commits March 3, 2026 20:06
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.
Copilot AI review requested due to automatic review settings March 4, 2026 08:01
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 (including description) 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)
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
cmd = privileged_cmd(['sudo', '-u', user, cls.WP_CLI_PATH, '--path=' + path] + command)
cmd = privileged_cmd([cls.WP_CLI_PATH, '--path=' + path] + command)

Copilot uses AI. Check for mistakes.
api_key.record_usage(ip_address)

from app import db
db.session.commit()
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
db.session.commit()
db.session.flush()

Copilot uses AI. Check for mistakes.
Comment on lines +44 to +46
@api_analytics_bp.route('/keys/<int:key_id>/usage', methods=['GET'])
@admin_required
def key_usage(key_id):
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
"""Get usage stats for a specific API key."""
period = request.args.get('period', '24h')

# Allow key owners to view their own usage
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +10
_backend = os.path.dirname(os.path.abspath(__file__))
if _backend not in sys.path:
sys.path.insert(0, _backend)
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
_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)

Copilot uses AI. Check for mistakes.
* @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]) {
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +15
const activeTab = validTabs.includes(tab) ? tab : defaultTab;
const setActiveTab = (t) => navigate(`${basePath}/${t}`, { replace: true });
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
return True


def privileged_cmd(cmd: Union[List[str], str]) -> Union[List[str], str]:
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +37
if isinstance(cmd, str):
if _needs_sudo() and not cmd.lstrip().startswith('sudo '):
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +42 to +43
if _needs_sudo() and cmd[0] != 'sudo':
return ['sudo'] + cmd
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
jhd3197 and others added 2 commits March 4, 2026 03:20
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.
@jhd3197 jhd3197 merged commit ffeabb1 into main Mar 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants