Commit Graph
65 Commits
Author SHA1 Message Date
Juan DenisandClaude Opus 4.8 478b24a3cb feat: Phase 3 team & scale — projects/environments, shared resources, PR previews, proxy stacks
- Project / Environment hierarchy (C2): Workspace -> Project -> Environment
  org model. New Project/Environment models + CRUD APIs, nullable
  applications.project_id/environment_id (opt-in, no destructive backfill),
  ProjectService.ensure_default, a Projects list + ProjectDetail (env tabs),
  a project/environment selector in the create wizard, and sidebar nav.

- Polymorphic shared resources facade (C9): ResourceTag + SharedVariableGroup
  /SharedVariable/attachment models keyed by (resource_type, resource_id),
  reusing the env-var Fernet encryption; SharedResourceService resolves merged
  variables (most-recent attachment wins) with secrets masked. /api/v1/shared
  endpoints + reusable TagsPanel/EnvironmentVariablesPanel + a Shared Variables
  management page. Existing per-resource tables untouched (facade first).

- PR preview environments (C3): ApplicationPreview + settings models, a
  PreviewService with pure domain-templating + reconcile (open PRs vs active
  previews) cores and best-effort provisioning (incl. guarded WordPress
  file+DB clone), a pull_request webhook endpoint, preview.* jobs, and a
  Previews tab on the app detail page.

- Per-server managed proxy stack (C6): opt-in Dockerized Traefik/Caddy as a
  Compose stack (host Nginx stays default and superior for PHP/WordPress).
  ProxyStack model + ProxyStackService with pure compose/config generators and
  versioned config backups, /api/v1/servers/<id>/proxy endpoints, and a Proxy
  tab on the server detail page.

Migrations 031-034 add the new tables/columns; the full chain applies cleanly
from an empty DB. Full backend suite: 871 passed, 14 skipped; frontend builds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 19:33:44 -04:00
Juan DenisandClaude Opus 4.8 a550f16baf feat: Phase 2 developer experience — build packs, config snapshots, catalog certification
- Build packs / zero-Dockerfile deploys (C1): new BuildpackService detects the
  stack from a cloned repo (Node/Python/Go/PHP/Ruby/Rust/static), produces a
  transparent build plan and a generated Dockerfile, and persists the plan +
  overrides on the Application. POST /api/v1/buildpacks/{detect,generate}; a
  BuildpackPreview shows the detected plan + editable overrides + Dockerfile in
  the create wizard and the app Build tab. Builds on the existing build_method
  plumbing instead of duplicating it.

- Deployment config snapshots + diff engine (C4): ConfigurationService captures
  an immutable, hashed snapshot of resolved config (env keys + masked values,
  domains, image/tag, build method, volumes) at every deploy and rollback; new
  DeploymentSnapshot model + /api/v1/apps/<id>/snapshots[/diff|/restore]. A
  DeploymentTimeline + ConfigDiffModal surface "what changed" and one-click
  restore in the app Deploy tab. Secret values are never serialized.

- Template catalog certification (C5 cont.): a whole-catalog validation test
  proves all 105 declarative templates conform to the documented schema; fixed
  the stale index.json (was 63/105 entries) to list every bundled template.

Migration 030 adds the buildpack columns + deployment_snapshots table. Full
backend suite: 820 passed, 14 skipped; frontend builds clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 18:49:04 -04:00
Juan DenisandClaude Opus 4.8 f47d0e1428 feat: Phase 1 foundation — status aggregator, API scopes, onboarding, template magic vars
Four foundational enhancements toward the deploy-code developer experience:

- Container status aggregator (C7): new ContainerStatusService applies a
  deterministic priority hierarchy (degraded > restarting > running:unhealthy >
  starting > running:healthy > exited > unknown) over an app's containers,
  cached with a short TTL. Exposed at /api/v1/status and pushed over a new
  container_status Socket.IO channel; Applications page now renders an
  aggregated ContainerStatusPill with sub-status tooltip.

- API token scopes + sensitive data masking (C10): require_scope() decorator
  enforces fine-grained scopes for API-key requests (pass-through for JWT),
  a canonical SCOPES catalog at /api/v1/api-keys/scopes, and a reusable
  sensitive_data_filter (mask_sensitive) honoring secrets:read. Frontend gains
  a grouped ApiKeyScopesModal picker and per-key scope pills.

- Server onboarding state machine (C8): new onboarding lifecycle
  (pending -> validating -> installing_prerequisites -> installing_docker ->
  pairing_agent -> ready/failed) with ServerOnboardingService, a
  server_onboarding_logs table, servers.onboarding_* columns, REST endpoints,
  and an OnboardingWizard surfaced on the server detail overview.

- Declarative template catalog (C5): documented catalog schema and
  magic-variable resolution (SERVICE_PASSWORD_/USER_/FQDN_/URL_/BASE64_*)
  layered onto the existing YAML template loader without changing behavior for
  templates that don't use them; GET /api/v1/templates/catalog/schema.

Migration 029 adds the onboarding table + columns. 60 new tests pass; frontend
builds clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 18:23:47 -04:00
Juan DenisandClaude Opus 4.8 d344302ac1 feat(domains): unify domains & DNS into one surface + admin-only Connections
- /domains is one table: app-linked domains + live zones from connected DNS
  providers (Cloudflare, ...) with provider badges. New GET /dns/portfolio
  (aggregates provider zones, marks which are adopted) and idempotent
  POST /dns/adopt (lazy-materialize a managed zone on demand).
- Every row opens one drawer = the unified DNS records surface
  (components/domains/DomainDnsPanel): live Cloudflare records via
  GET /dns/provider-records (no adopt needed), type badges, proxied=>HTTPS hint,
  inline Add record, deep-links to Cloudflare ops / full DNS page. Fixed-layout
  table (no horizontal scroll); actions moved into the drawer header.
- Registration expiry/registrar from Cloudflare Registrar + lazy RDAP fallback
  (GET /dns/registration), persisted/cached in the new domain_registrations
  table and merged into the portfolio so it survives a refresh. New
  frontend/src/utils/expiry.js formatExpiry() date util.
- Connections moved to admin-only (Settings Admin group + isAdmin gate;
  @admin_required on /api/v1/connections); CF connection card links to Domains.
- Cloudflare client: expose each zone's account_id; add list_registrar_domains.
- Tests: backend/tests/test_dns_portfolio.py.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 00:34:55 -04:00
Juan DenisandClaude Opus 4.8 5836294c4d feat(cloudflare): R2 / KV / D1 developer platform (Phase 6)
Add a Storage tab listing and managing Cloudflare's account-scoped storage
primitives — R2 buckets, KV namespaces, and D1 databases. Management only
(list/create/delete); the object/key/row data planes are out of scope.

- CloudflareClient: r2/buckets, storage/kv/namespaces, d1/database list+create
  +delete.
- CloudflareService: combined list_storage (each product fetched independently so
  a missing token scope degrades to a per-product error, not a dead tab),
  validated create/delete for each. R2 bucket names validated S3-style.
- /api/v1/cloudflare/zones/:id/storage* routes (read any user; writes admin).
- StoragePanel (three generic create/list/delete sections; R2 notes its
  S3-compatibility for future backup targeting); api methods; SCSS.

No new tables — wiring an R2 bucket as an S3 backup backend (minting scoped R2
keys) is a deliberate follow-up, noted in the UI.

Tests: aggregate listing + per-product error degradation, R2 name validation,
create/delete, KV/D1 required-field guards (6).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:39:12 -04:00
Juan DenisandClaude Opus 4.8 2f1999018d feat(cloudflare): Cloudflare Tunnels (Phase 5)
Add a Tunnels tab for creating and managing Cloudflare Tunnels (cloudflared) —
exposing a local/private service through Cloudflare's edge with no public IP.
Clearly distinct from ServerKit's WireGuard remote-access tunnels (always
labelled "Cloudflare Tunnel" in the UI). Account-scoped; account resolved from
the zone.

- CloudflareTunnel model: records the connector token (encrypted at rest) and
  owning connection per (account, tunnel_id).
- CloudflareClient: cfd_tunnel create (config_src=cloudflare) / list
  (is_deleted=false) / delete / token / connections / configurations get+put.
- CloudflareService: create (returns + stores the one-time token, yields the
  cloudflared install command), list (managed-flagged), delete, fetch install,
  and public-hostname routing — sets the ingress config (always re-appends the
  required http_status:404 catch-all) and best-effort upserts the proxied CNAME
  hostname→<id>.cfargotunnel.com via the shared ownership-guarded DNS path.
- /api/v1/cloudflare/zones/:id/tunnels* routes (read any user; writes admin).
- TunnelsPanel (create form + one-time install box w/ copy, tunnel list with
  per-tunnel install reveal and public-hostname add/remove); api methods; SCSS.

Tests: list is_deleted param, create config_src, name required, token stored
encrypted + install string, managed-flagging, delete prunes local row, ingress
built with catch-all last (7).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:34:32 -04:00
Juan DenisandClaude Opus 4.8 02774f741e feat(cloudflare): Workers edge hosting (Phase 4)
Add a Workers tab to the Cloudflare Zone Settings page for deploying edge
scripts and managing Worker routes. Workers are account-scoped, so the owning
account is resolved from the zone — the whole feature reuses the existing
Cloudflare DNS connection (no new credential).

- CloudflareWorker model: records the source ServerKit uploaded per (account,
  name) so a worker can be tracked and re-deployed (created via create_all).
- CloudflareClient: zone→account lookup, list/delete scripts, and a stable
  multipart PUT /scripts/{name} module upload (the still-beta resource-oriented
  Workers API is deliberately avoided per the roadmap's fallback note), plus
  zone Worker routes list/add/delete.
- CloudflareService: list (live scripts flagged when ServerKit-managed + routes),
  deploy (validated lowercase name, records source, optional route attach),
  delete, route add/delete.
- /api/v1/cloudflare/zones/:id/workers* routes (read any user; writes admin).
- WorkersPanel component (deploy form with a starter script, worker list, routes
  list); api methods; SCSS.

Tests: multipart upload shape, name validation, deploy records source, list
managed-flagging, delete prunes the local row (5).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:27:36 -04:00
Juan DenisandClaude Opus 4.8 5ec5be4b31 feat(cloudflare): WAF custom rules (Phase 3)
Add a WAF tab to the Cloudflare Zone Settings page for managing custom firewall
rules (the http_request_firewall_custom phase entry-point ruleset).

- CloudflareClient: ruleset list/get + phase-entrypoint create (PUT) + per-rule
  POST/PATCH/DELETE.
- CloudflareService: list rules (empty when no custom ruleset yet, distinguished
  from an auth error by listing rulesets first), add rule (creates the ruleset on
  first use), update/delete, and three one-click presets — lock WordPress admin
  to an IP, block common exploit paths, challenge suspicious bots. The IP in the
  lock preset is validated with ipaddress so it can't inject expression syntax;
  rule actions are constrained to a safe terminal subset.
- /api/v1/cloudflare/zones/:id/waf/* routes (list any user; add/preset/update/
  delete admin).
- WafPanel component (preset picker + custom-rule form + active-rules list with
  enable toggle and delete); api methods; SCSS.

Tests: ruleset discovery, empty vs auth-error, create-on-first-rule vs append,
action validation, preset IP validation + safe expression, update/delete (10).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:20:26 -04:00
Juan DenisandClaude Opus 4.8 6bc0ac36e5 feat(cloudflare): cache purge (Phase 2)
Add Cloudflare cache management to the Zone Settings page. Purge everything (with
a confirm) or purge specific URLs (one per line, capped at 30 to match Free/Pro
limits); hosts/prefixes/tags are accepted by the API for Enterprise plans and
their plan errors are surfaced verbatim.

- CloudflareClient.purge_cache(zone_id, payload).
- CloudflareService.purge_cache: validates intent (raises on empty), caps files
  at 30, normalizes the payload.
- POST /api/v1/cloudflare/zones/:id/purge-cache (admin).
- Actions tab gains a "Purge cache" card (purge-everything button + URL list);
  api method; SCSS.

Tests: client payload, purge-everything, 30-file cap, empty-raises, provider
error surfaced (5 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:12:20 -04:00
Juan DenisandClaude Opus 4.8 125b1e4553 feat(cloudflare): zone settings page (Phase 1)
Add a Cloudflare Zone Settings surface on top of the existing Cloudflare DNS
connection — SSL/TLS, Speed, Caching and Security toggles plus a one-click
"recommended hardening" preset. Reuses the connected DNSProviderConfig
credential and shared CloudflareClient, so auth/encryption-at-rest are not
re-implemented.

Backend:
- CloudflareClient: generic v4 request() helper + zone-settings get/update
  (envelope normalized to {success, error?, result?}).
- CloudflareService: resolve zone+credential by ServerKit DNS zone id, curated
  setting groups (UI metadata), get/update setting, apply recommended preset
  with per-setting reporting.
- /api/v1/cloudflare blueprint: settings GET / GET-one / PATCH + apply-preset
  (reads any user, writes admin; mutations captured by the audit fallback).

Frontend:
- CloudflareZoneSettings page (tabbed SSL/TLS · Speed · Caching · Security ·
  Actions) with declarative toggle/select/HSTS controls and optimistic save.
- Route /cloudflare/zones/:zoneId, "Cloudflare" link from Cloudflare-managed
  DNS zones, api module, SCSS.

Tests: client envelope/zone-settings + service resolution guards, indexing,
and preset reporting (11 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:08:38 -04:00
Juan DenisandClaude Opus 4.8 7b9ae4f934 feat(backups): protection panel UI + global cost view
Shared ProtectionPanel (status, schedule, history) rendered for WordPress (Backups tab + Settings) and Services (Settings → Backups), plus a calendar view, detail/restore drawers, and storage-cost columns/settings/KPIs on the global Backups page.

- components/backups: ProtectionPanel, ProtectionStatusCard, ScheduleCard, BackupHistoryList, BackupCalendar, BackupDetailDrawer, RestoreDrawer, format helpers
- api/backupProtection: generic policy/runs methods over targetType
- WordPressDetail + service-detail SettingsTab render the shared panel
- Backups page: cost rates settings, Site/Cost columns, cost KPI cards

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:53:34 -04:00
Juan Denis edf6260dee fix(build-release): make release builder work on Windows/Git Bash
- Replace rsync with tar-based copy to avoid missing rsync on Windows/Git Bash
- Exclude backend/venv, backend/.venv, backend/.venv-wsl, and broken WSL symlinks
- Exclude ./backups, backend/dev-data/backups, backend/instance/backups, and scripts/test/output
- Exclude scratch images (PNG/JPEG/JPG), logs, and tmp files from the tarball
- Pack with tar --transform so /opt/serverkit prefix is created without cross-device moves
- Reduce release tarball from 13 GB back to ~6 MB
2026-06-22 16:52:34 -04:00
Juan DenisandClaude Opus 4.8 37707e7b5d feat(dns): "Changes to your Cloudflare" UI — activity feed + zone mirror (Phase 2 frontend)
#7 Surface the Phase 2 backend:
- DnsActivity: a per-connection "Recent changes" feed (action, record, result
  badge, error) from GET /dns/changes, expandable on each DNS connection in
  Settings -> Connections.
- DNS Zones page: a "ServerKit records / In your provider" toggle; the provider
  view (GET /dns/<id>/mirror) lists every live record badged ServerKit vs External,
  external records read-only/muted ("ServerKit never modifies external records").
- api: getDnsChanges() + getZoneMirror().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 16:40:26 -04:00
Juan Denis 0f4e5821da feat: add dismissible system notices for common misconfigurations
- Add GET /api/v1/system/notices endpoint (admin-only)
- Detect missing canonical domain, sites base domain, server public IP, and wildcard HTTPS
- Add SystemNotices React component with dismiss persistence in localStorage
- Render notices inside DashboardLayout so they appear on every page
- Add scoped SCSS for warning/info/error notice banners
2026-06-22 14:42:09 -04:00
Juan DenisandClaude Opus 4.8 70f8697586 feat(jobs): admin Jobs UI page over the unified job API (Phase 9)
Add /jobs — the single pane to observe and manage all background work, built
on the /api/v1/jobs API. Mirrors the DeliveryLog/Telemetry admin pages.

- Jobs table polls every 5s: status Pills (succeeded/running/pending/failed/
  cancelled), kind, owner, attempts, age. Status/kind filters. Per-row Cancel
  (pending/running) and Retry (failed/cancelled) with toast feedback. Row
  expands to a detail view (payload/result/error/correlation/timing) via getJob.
- Scheduled-jobs table: name, kind, schedule (cron or "every Nh"), next/last run,
  with Run-now and Pause/Enable.
- Stat cards (total/running/pending/succeeded/failed) from /jobs/stats.
- Wiring: services/api/jobs.js module bound into ApiService; route + page title
  in App.jsx; "Jobs" item in the sidebar "system" group; _jobs.scss imported
  in main.scss. Admin-gated client-side via useAuth().isAdmin.

Lint clean (0 errors) and production build passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 21:28:41 -04:00
Juan Denis 3d3975fa3a feat(telemetry): unified system event stream with correlation
Add SystemEvent model, TelemetryService, /api/v1 telemetry endpoints, and
a /telemetry UI page. Instrument audit, notification, webhook, backup,
deployment, and monitoring paths. Add correlation_id to Notification,
EventDelivery, and DeploymentJob so related events can be grouped.

- 18 backend tests added and passing
- Frontend production build clean
2026-06-21 20:19:57 -04:00
Juan DenisandClaude Opus 4.8 a33b2f7f38 feat(frontend): notification center, delivery log, email providers
- NotificationsContext + header bell/dropdown (sidebar + mobile top bar)
  with a live unread badge over Socket.IO and a /notifications history page.
- Admin /admin/notifications delivery log (stat cards, status/channel
  filters, retry) and an email-provider management UI (add/test/
  set-default/delete) for SMTP/SendGrid/Postmark/SES/Mailgun.
- api/notifications.js methods, socket 'notification' forwarding, a timeAgo
  util, and themed sk-notif* / sk-dlog / sk-eprov styles.

Builds clean (vite) and lints clean (eslint exit 0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:57:18 -04:00
Juan Denis 45f754abc0 feat(workspaces): improve workspace switching and secrets/webhooks UI
- Update workspace API and service for workspace context handling
- Refine Sidebar and WorkspaceSwitcher components
- Update sidebar navigation items for workspace-aware routing
- Enhance SecretsWebhooks page and API client integration
2026-06-21 18:32:25 -04:00
Juan Denis 32e6def0e6 Add ClamAV start action and UI posture fixes
Add a POST /security/clamav/start endpoint and SecurityService.start_clamav() to enable+start the ClamAV daemon (tries clamav-daemon and clamd). Add unit tests that mock ServiceControl to verify success/failure and auth. Wire a startClamAV API call into the frontend and extend the Security Overview: richer posture UI, one-click fixes (install, start service, init integrity, update defs), KPIs, icons, and accessibility improvements. Update related styles and file-manager minor styles. This improves operator workflows by allowing a one-click "Start service" posture fix and provides immediate UI feedback when fixes run.
2026-06-21 01:54:51 -04:00
Juan DenisandClaude Opus 4.8 03504c6517 feat(connections): GitLab/Gitea/Bitbucket repo pickers + path selector
Adds source-connection support for browsing repositories on GitLab, Gitea, and
Bitbucket (new *RepoPicker components) plus a PathSelector, wired through
RepoConnectForm / GitProviders / ConnectionsHub / providerCatalog and the
sourceConnections + files APIs, backed by additions to the source_connections
API and service.

Bundled from in-progress work in a concurrent session at the user's request.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 00:20:10 -04:00
Juan Denis 9b4618b24b feat(queue-bus): introduce ServerKit Queue Bus under Operations
- Add pluggable queue bus with SQLAlchemy backend (Redis-ready interface)
- Models: QueueGroup, Queue, QueueMessage with retries, visibility timeout,
  delayed delivery, priority ordering, and dead-letter handling
- REST API at /api/v1/queue for groups, queues, messages, and stats
- Plugin SDK: from app.plugins_sdk import queue
- Operations UI page with group/queue/message management and send-message form
- Migrate webhook deliveries from raw threading.Thread to the queue bus
- Add webhook consumer with retry/dead-letter support
- Migration 022_queue_bus and backend tests
2026-06-20 22:25:06 -04:00
Juan DenisandClaude Opus 4.8 4cfc3cd0a6 fix(secrets): repair load + tab layout on the Secrets/Webhooks page
The api module called this.get/post/patch/delete, which the ApiService doesn't expose (only request(path, {method, body})) — so every load threw 'this.get is not a function'. Rewrote it to use request() like the other api modules. Also dropped an erroneous className='tabs' on the <Tabs> root: that class (display:flex, meant for the TabsList strip) made the root a row, so the panel rendered beside the tabs instead of below them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 12:55:15 -04:00
Juan DenisandClaude Opus 4.8 70883d50a9 feat(ui): WAF panel + tab on the app detail page
- API client: WAF methods (getWafPolicy/updateWafPolicy/applyWaf/
  getWafEvents/getWafStatus/installWaf) in containerOps.js.
- WafPanel.jsx: install banner (+ install action), mode (off/detect/block)
  with descriptions, paranoia level + anomaly threshold, a disabled-CRS-rule
  chip editor, Save (saves + applies) + Re-apply (surfaces manual_include
  when no vhost is found), and a recent-events table.
- ApplicationDetail: a "WAF" tab (nginx-served apps), wired like Container Ops.

Build passes; new file lint-clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 14:41:26 -04:00
Juan DenisandClaude Opus 4.8 24d5362493 feat(ui): surfaces for DDNS, image-update, auto-sleep, auto-scale, GPU
- API client: DDNS methods (dns.js) + per-app container-ops/GPU methods
  (new containerOps.js), auto-bound via index.js.
- ApplicationDetail: a "Container Ops" tab (Docker apps) via the new
  ContainerOpsPanel — image-update check/apply, auto-sleep toggle +
  sleep/wake, and auto-scale policy + manual scale.
- GpuMonitor page (/gpu): per-GPU cards (utilization, VRAM, temp, power,
  fan, driver) + compute-process table; clean empty state when no GPU.
- DynamicDns page (/dynamic-dns): DDNS host CRUD with a one-time token +
  ready-to-use update URL, regenerate-token, and delete.
- Routes + sidebar nav (GPU Monitor, Dynamic DNS) + page SCSS.

Build passes; new files lint-clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 10:34:45 -04:00
Juan Denis 2b7a98c348 feat: canonical domain + encryption key bootstrap
- Auto-generate SERVERKIT_ENCRYPTION_KEY in production when missing.
- Detect canonical domain from Host/X-Forwarded-Host; persist via SystemSettings.
- Expand CORS origins dynamically to include the canonical domain.
- Add SystemTab UI to view/save detected panel domain and HTTPS preference.
- Install script writes key, prompts for PANEL_DOMAIN, and sets nginx IP→domain redirect.
- Add backend tests for key bootstrap and domain detection helpers.
2026-06-19 01:34:02 -04:00
Juan Denis bf9fee131e feat: add secrets manager and inbound webhook gateway
- Encrypted vault + secret models with Fernet encryption
- Webhook endpoint + delivery log models with HMAC verification
- SecretVaultService / WebhookGatewayService business logic
- /api/v1/vaults, /secrets, /webhooks REST endpoints (JWT + public receive)
- Migration 020_secrets_webhooks
- Frontend Secrets & Webhooks page, API methods, sidebar, styles
- Add SERVERKIT_ENCRYPTION_KEY to .env.example
2026-06-19 01:33:46 -04:00
Juan Denis 70a70642c1 feat(services): support manual/local apps and zip uploads
- Extend Application model with source, compose_file, systemd_unit,
  managed_by, version, and upload_path columns.
- Add migration 017_manual_apps for the new columns.
- Add POST /apps/manual to register existing server paths/systemd units.
- Add POST /apps/upload with versioning, rollback, and .env preservation.
- Update DockerService compose helpers to accept a custom compose_file.
- Update ProcessService to query systemd units and compose projects.
- Update apps API start/stop/restart/status/delete to honor compose_file
  and avoid deleting unmanaged manual paths.
- Add Manual/Local and Upload ZIP source modes to NewService.
- Show source badges in Services list and disable Git controls for
  manual/upload apps in ServiceDetail.
- Add version list, rollback, and new-version upload UI for upload apps.
2026-06-18 22:16:00 -04:00
Juan DenisandClaude Opus 4.8 7cf8d4e18a feat(remote-access): NAT-traversing WireGuard tunnels to expose private services
Self-hosted tunneled reverse proxy: a service on a NAT'd host (e.g. a home
Jellyfin box) gets a public HTTPS hostname with no port-forwarding, by pairing
two agents over WireGuard. Implements Phases 0-3 of docs/REMOTE_ACCESS_ROADMAP.md.

Agent (Go):
- new internal/wireguard package: Manager interface + kernel backend (wg/ip)
  and a userspace netstack backend (wireguard-go + gVisor) so Windows/macOS
  peers need no driver/admin; in-process keygen returns only the public key
  (private keys never leave the host)
- wireguard:keygen/interface/peer/status/forward/unforward + firewall
  :allow_port/:deny_port commands; wireguard + firewall capability probes
- TCP forwarder (tnet.ListenTCP / net.Listen -> dial localhost) carries
  traffic to the real service behind a netstack peer

Backend (Python):
- Tunnel + ExposedService models; tunnel_netutil (subnet allocator, health);
  tunnel_broker_service (keygen->up->peer->verify, firewall open, reconcile-on-
  reconnect); tunnel_publish_service (forward -> nginx -> DNS -> auth -> cert)
- nginx remote-upstream vhost (WebSocket + proxy_buffering off)
- /api/v1/tunnels CRUD + /<id>/services publish/unpublish
- panel-authoritative reconcile hooked into the agent gateway on reconnect

Frontend (React):
- Remote Access page (tunnels + exposed services, status, teardown) and an
  "Expose a Local Service" wizard; new services/api/tunnels.js

Verified: go build (win/linux) + vet + go tests (forwarder + no-leak parsers);
py_compile + pytest (netutil, reconcile, nginx template); create_app boot;
eslint + npm run build. Live multi-host run pending.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 23:20:00 -04:00
Juan DenisandClaude Opus 4.8 fd2313077f Polish connections: domain-expiry alerts, S3 image preview, encryption-health banner
- Domain-expiry notifications: a daily scheduler (RegistrarService.notify_expiring)
  fires through the notification channels when a registrar domain crosses 30/14/7/1
  days or expires, de-duped via a small state file so each crossing alerts once.
- S3 image preview: ImageThumb is now S3-aware (loads objects via short-lived
  presigned URLs); threaded through FileCard / PreviewDrawer / FileManager.
- Encryption-health banner: the Connections hub consumes GET /api/v1/connections
  and warns if any credential is not encrypted at rest (hidden in the happy path)
  — the registry's first real consumer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 19:43:00 -04:00
Juan DenisandClaude Opus 4.8 bbe6bee267 Unify credential encryption + add a read-only connection registry (#18)
- Encrypt the last plaintext credential store: CloudProvider.api_key_encrypted is
  now Fernet-encrypted on write and decrypted in _auth_headers, with an idempotent
  encrypt_legacy_secrets() migration run at startup. All five stores (source, DNS,
  cloud, registrar, storage) now encrypt identically via app.utils.crypto.
- Add ConnectionRegistry + GET /api/v1/connections: one normalized, secret-free
  list of every connected external account (the "what's connected" source of
  truth). Frontend api.getAllConnections().
- The full write-side "one model replaces five" migration is deliberately not done
  — it would risk five working subsystems for no user-facing benefit. The uniform
  encryption + read registry deliver #18's practical value.

Verified by booting create_app('testing') and running the registry live (returns
a list; /api/v1/connections present in the URL map).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 10:47:59 -04:00
Juan DenisandClaude Opus 4.8 845df9959e Add S3 bucket browsing to the Files app (#14, #15)
- backend: StorageProviderService.s3_* (browse/read/write/upload/delete/
  presigned-get) + /api/v1/files/s3/* routes, reusing the configured backup
  bucket — no new credentials.
- frontend: an "S3 bucket" target in the File Manager. UI paths stay slash-rooted
  and map to S3 keys server-side, so breadcrumbs/history work unchanged; virtual
  folders from prefixes; presigned-URL download. Folders/rename/permissions are
  disabled and the local-only sidebar is hidden on S3. TargetPicker gained a
  backward-compatible extraOptions prop.
- docs: mark #14/#15 done (Phase 4).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 10:21:39 -04:00
Juan Denis c1d4653f6c Add registrars, GitLab, DO/Godaddy DNS and SMTP relay
Introduce a broad Connections expansion: add RegistrarConnection model, RegistrarService and /api/v1/registrars endpoints to surface domain portfolios and expiry. Add EmailRelayService and API routes plus Postfix relay wiring to configure/test/disable outbound SMTP. Extend DNSProviderService with DigitalOcean and GoDaddy implementations and helpers. Add GitLab support to source connection service and routes. Frontend: expand Connections hub, provider catalog, modal bodies, provider icons, RegistrarPortfolio component, API client methods and styles. Add docs/CONNECTIONS_ROADMAP.md describing roadmap and intent.
2026-06-15 09:19:56 -04:00
Juan DenisandClaude Opus 4.8 0a74e5670d feat(sites): wildcard HTTPS for managed subdomains
One-time operator setup that makes every managed subdomain HTTPS. New
SitesHttpsService.setup creates the *.<base> + <base> A records via a connected
DNS provider and issues a wildcard Let's Encrypt certificate over DNS-01,
reusing that provider's credentials — then flips sites_https_enabled on.

- AdvancedSSLService.issue_wildcard_cert now supports route53 (AWS env creds) as
  well as cloudflare, takes an email, installs the matching certbot DNS plugin
  best-effort, and returns the cert/key paths.
- SiteDomainService gains https_enabled / wildcard_cert_paths / covers. create_site
  installs new subdomain sites at https when enabled, and _write_app_vhost serves
  the wildcard cert on vhosts whose every domain it covers (custom domains keep
  their own cert).
- NginxService.create_site takes optional ssl_cert/ssl_key and bakes a 443 block +
  HTTP->HTTPS redirect (idempotent via full regen).
- sites_base_domain / server_public_ip / sites_https_enabled are now discoverable
  settings. Admin endpoints GET/POST /admin/sites-https/{status,setup}, surfaced
  in Settings → Site as a "Managed Sites Domain & HTTPS" panel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:52:30 -04:00
Juan Denis 986909a955 Surface Docker DBs, add base port & migration fixes
Expose and surface containerised databases and introduce managed app base port control. Backend: add endpoint to list databases across all Docker apps, robustly resolve compose container names, include docker DB user when querying, compute migration needs from live heads and self-heal orphaned alembic_version entries by stamping to head, and add the managed_app_base_port system setting. Template service now honours the managed_app_base_port and WordPress template default HTTP port updated to 8300. Frontend: add react-icons brand icons and DatabaseBrands component, show Docker-hosted DBs under their engine nodes with a docker badge, platform-aware console shortcut label, pass DB user to docker table/query API calls, add API client header merge fix, UI for managing base port in settings, enhanced migration history UI (backup/apply/resync flows, confirm dialog, toasts), and various style tweaks and color additions.
2026-06-06 23:29:22 -04:00
Juan DenisandClaude Opus 4.8 4dca43b6b0 feat(workspaces): sharing UI for per-site ACL grants (#33)
Completes the per-site ACL feature with UI on top of the backend (d9a5ec7).

- A per-app 'Share' action in the Workspaces Resources modal opens an inline
  sub-view: current grantees with Revoke, plus a grant-access list of users
  (the owner and existing grantees are filtered out).
- Client methods getAppGrants / grantAppAccess / revokeAppAccess.

Verified: frontend lint-clean (no new warnings) + production build. The grant
endpoints are covered by backend tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 12:03:38 -04:00
Juan DenisandClaude Opus 4.8 35c7a73d8c feat(workspaces): manage servers in the workspace Resources modal (#33)
Completes the reassignment feature symmetrically — the server reassign endpoint
shipped earlier (e89415f) was API-only; now it has UI.

- getServers gains an allWorkspaces bypass (empty X-Workspace-Id header) and a
  setServerWorkspace client method (mirrors apps).
- The per-workspace modal is now a 'Resources' modal with both Applications and
  Servers sections, each with move-in / move-out.

Verified: frontend lint-clean (no new warnings) + production build. The server
endpoint itself is already covered by backend tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 11:18:46 -04:00
Juan DenisandClaude Opus 4.8 e89415f3e0 feat(workspaces): reassign apps/servers between workspaces (#33)
Completes the organizing loop — existing resources were stuck wherever the
backfill put them (Default); now they can be moved into client workspaces.

- PUT /apps/<id>/workspace (owner-or-admin on the app) and
  PUT /servers/<id>/workspace (developer+), both requiring the TARGET be a
  workspace the caller can access (member or admin). A null target moves the
  resource back to Default.
- UI: an 'Apps' management modal on each Workspaces card (mirrors the Members
  modal) with move-in / move-out. It fetches with allWorkspaces (an empty
  X-Workspace-Id header) so it can see apps in other workspaces to move them in,
  sidestepping the ambient scope.
- Fixed a real bug caught by tests: the app ownership check compared app.user_id
  to the stringified get_jwt_identity() (int != str -> spurious 403); now uses
  user.id.

Verified: 2 new endpoint tests (ownership + target-membership + null->Default +
role gates), full suite 122 passed, frontend lint-clean + production build.
Servers reassignment is API-only for now; the modal is apps-only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 09:32:30 -04:00
Juan DenisandClaude Opus 4.8 567d6059f7 feat(workspaces): workspace-scoped brand color recolors the panel (#33)
Selecting a client workspace now recolors the whole panel to that client's brand
— the visible payoff of the workspace effort.

- A workspace's primary_color (already on the model) is now editable via a color
  picker added to the Workspaces create modal.
- WorkspaceSwitcher mirrors the active workspace's color into a workspace_accent
  localStorage key; ThemeContext applies it via the existing applyAccentToDOM with
  precedence over the user's personal accent (workspace_accent || accentColor),
  recoloring the logo gradient, buttons, and highlights.
- Deterministic (no effect-ordering races): switching reloads and the value is
  read once on mount. Cleared on logout and on a stale selection; reverts to the
  user accent on 'All workspaces'. Default color is the app accent, so a workspace
  is unbranded unless a custom color is chosen.

Verified: frontend lint-clean (no new warnings) + production build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 09:19:57 -04:00
Juan DenisandClaude Opus 4.8 ddff69020b feat(workspaces): active-workspace selector + ambient X-Workspace-Id header (#33)
Makes the workspace scoping foundation user-visible — the research flagged the missing 'current workspace' context as the core gap #33 had to close.

- WorkspaceSwitcher (sidebar): self-contained selector that reads/writes an
  active_workspace_id in localStorage, fetched from the user's workspaces. Hides
  for single-workspace installs and drops a stale selection on load.
- services/api/client.js: sends the active workspace ambiently as X-Workspace-Id
  on every request (endpoints that don't honor it ignore it); cleared on logout.
- Switching reloads so all lists re-fetch under the new scope.

Backend resolve_workspace_id is lenient (prior commit) so a stale header can
never break the apps/servers lists. Verified: frontend lint-clean + production
build; the header->scoping path is covered by the backend API tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 08:54:01 -04:00
Juan DenisandClaude Opus 4.8 9cab065dc5 feat(ai): add core AI assistant primitive powered by Prompture
AI is a core ServerKit primitive (not a plugin): an Intercom-style bubble + slide-in drawer on every dashboard page, with a tools+page-context assistant mode and a plain simple chat mode, SSE streaming, conversation persistence, and guarded write actions (the model proposes; the user approves).

Plugins EXTEND the assistant rather than rebuilding it: backend via app.plugins_sdk.ai (reg.tool + register_context_provider, discovered from a plugin.json ai block with install/enable/disable hooks); frontend via useServerkitAI() and a contributions.ai category (suggested_prompts, tool_renderers). The marketplace gains an ai category for discovery.

Backend: ai_service (Prompture Conversation + ProviderEnvironment + guardrails), ai_tool_registry singleton, ai_tools_builtin (core.* tools), the /api/v1/ai blueprint (SSE via a worker-thread + queue bridge, single-gevent-worker safe; in-thread confirmation gate), AiConversation/AiMessage/AiPendingAction models + migration 013, encrypted ai_* settings. Frontend: AIContext + components/ai/*, AI settings tab. Powered by Prompture (installed editable; requirements pinned).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 02:39:05 -04:00
Juan Denis 9f7bd23f3c Improve plugin loading, API client & marketplace UI
Several changes to plugin handling, API client behavior, and the marketplace UI:

- Backend: added explicit '' route decorators for marketplace and plugins endpoints (GET/POST) to ensure routes mount at both '' and '/'.
- Frontend: make Git page accept a basePath prop and update serverkit-git plugin export to render GitPage at /git-ext.
- Auth/API: normalize API base URL, update token-expiry handling to dispatch a global serverkit:auth-expired event (client) and listen for it in AuthContext to clear user state; refresh token logic preserved on JWT 401s.
- Plugins/contributions: add build-time plugin manifest support and fallback for contributions when backend endpoint is unavailable; parse local plugin manifests and tag contributions with plugin slugs.
- Plugin loader: internalize getInstalledPlugins function signature.
- Marketplace UI: remove the submit-extension modal and form, replace with an Import ZIP flow and make tabs controlled via state; remove related SCSS styles.
- API & sockets: fix plugin API URL encoding/format and compute socket URL robustly for dev/prod.

These changes improve offline/dev experience (Vite dev server), make plugin contributions resilient when the backend is absent, and simplify the marketplace extension import workflow.
2026-05-03 17:17:32 -04:00
Juan Denis b4f5a466ce Add audit fallback, builtin extensions, and ports
Introduce fallback audit logging and enrich audit tooling; add builtin extension discovery/install; and update default launcher ports and related docs/config.

Key changes:
- New middleware app.middleware.audit registers an after-request fallback that records authenticated mutating API requests when routes don't emit explicit audit logs.
- Audit model/action constants extended and AuditService enhanced (request context handling, redaction for sensitive settings, optional commit flag, sets g.audit_logged, emits events).
- Routes/services updated to create explicit audit entries for marketplace and plugin operations (create/update/publish/install/uninstall/enable/disable) and SSO/settings flows switched to use AuditService.
- Added tests for audit logging behavior and redaction (backend/tests/test_audit_log.py).
- Plugin service: added BUILTIN_EXTENSIONS_DIR, list_builtin_extensions and install_builtin_extension; plugin API endpoints to list/install builtin extensions.
- Contribution system extended to support layouts and route layout metadata; frontend wiring updated to surface standalone/custom layouts and extension routes.
- Launcher port defaults changed (backend -> 47927, frontend -> 41921). Updated backend .env.example, config CORS defaults, Dockerfiles and docker-compose to use SERVERKIT_BACKEND_PORT, and many docs/README files and frontend envs to reflect new ports.
- Minor frontend cleanups and new builtin extension example (serverkit-git) plus associated manifest and frontend re-export.

These changes improve observability/security for mutating APIs, enable opt-in builtin plugins, and align local dev/run ports with the launcher defaults.
2026-05-03 15:57:02 -04:00
Juan Denis ddcf0b2f5f Add plugin contributions system, SDK, and integration
Introduce a first-class plugin contribution system and SDK, plus frontend integration and installer enhancements.

Backend:
- Add /plugins/manifest-spec and /plugins/contributions endpoints to expose the plugin.json contract and merged active-plugin UI contributions.
- Add app/plugins_sdk for plugin authors (current_user, logger, audit, jwt helpers).
- Add ContributionService to aggregate active plugin contributions (nav, routes, page_titles, command_palette, widgets).
- Marketplace now hands off to plugin installer when an extension has a source URL and enforces admin-only installs in the marketplace API.
- PluginService: run lifecycle hooks (install/uninstall) and install declared template dependencies (best-effort, recorded/logged) during plugin installs; surface template/manifest fields on InstalledPlugin.to_dict; surface linked InstalledPlugin status on ExtensionInstall.to_dict.

Frontend:
- Add runtime contributions loader (plugins/contributions.js) with useContributions hook and resolveComponent/getPluginModule helpers.
- Add SDK re-exports for plugin frontends (plugins/sdk/index.js) and Vite alias 'serverkit-sdk'.
- Integrate contributions across UI: Sidebar, CommandPalette, PluginLoader (declared widgets + legacy fallback), PageTitleUpdater, DashboardLayout (refreshContributions), and route injection via new ExtensionRoutes hook loaded in App.jsx.
- Add API client getPluginContributions and adjust PluginLoader discovery patterns.

Other:
- Add .extension-platform-plan/ to .gitignore.

Overall this enables declarative plugin-driven UI integration (sidebar items, SPA routes, page titles, command palette entries, and widgets), lifecycle hooks, and template dependency installs while keeping legacy behavior for older plugins.
2026-05-03 13:54:40 -04:00
Juan Denis 99abf8f147 Add repository manifest detection and templates
Introduce RepositoryManifestService to detect deployment manifests (ServerKit, Render, Railway, Compose, app.json, Dockerfile, Nixpacks) and recommend app/build settings. Add backend integration: analyze repo during import (apps.create_app_from_repository), new GitHub manifest API route, and SourceConnectionService helpers to list root files and fetch file contents from GitHub. Pass resolved dockerfile_path/custom build/start commands into build configuration. Add unit tests for the manifest service. Frontend: add template support and manifest UI in NewService.jsx, new API call inspectGithubRepositoryManifest, and related SCSS styles for templates/manifest display. Misc: updated imports and minor UX messaging changes.
2026-05-03 07:07:57 -04:00
Juan Denis 96db8df5ad Add GitHub source connections & repo picker
Introduce source provider connections to allow OAuth-backed GitHub repository selection and authenticated cloning. Backend: add SourceConnection model, SettingsService keys for GitHub OAuth, and a SourceConnectionService that handles OAuth flow, token storage (encrypted), repo/branch listing, and authenticated clone URL generation. Expose new API blueprint under /api/v1/source-connections with endpoints for status, authorize, callback, repos, branches, disconnect, and admin config. Update app creation flow to accept source_connection_id and repository_full_name, use authenticated clone URLs for cloning/deploy, and sanitize clone errors to show public repo URLs. Frontend: add SourceConnectionsTab UI, source connection callback route/component, extend App routes, and revamp New Service page to support connecting GitHub, picking repositories/branches, or using a manual git remote; update API client and styles accordingly. Note: database migration will be required to create the source_connections table and admins must configure GitHub client ID/secret.
2026-05-03 06:54:29 -04:00
Juan Denis c18d0d8ae5 Add New Service (repo) creation and UI
Introduce creating services from Git repositories and related UI changes.

Backend: add /apps/from-repository endpoint to validate input, clone repositories, detect build/app type (via BuildService), configure build and deploy (via GitService), persist Application records, and perform cleanup on failure. Add helper utilities for slugifying, safe repo URLs, path validation, and attaching deploy configs to app responses. Make git clone command branch optional.

Frontend: add NewService page, route (/services/new), sidebar entry and buttons for creating a new repo-based service, API client method createAppFromRepository, and import new styles. Update Services, ServiceDetail, Deployments, and Servers pages with UI/UX improvements (deploy actions, repo display sanitization, new icons, deployment CTA, and extensive servers rail/refactor). Add _new-service.scss and include it in main styles.
2026-05-03 06:28:21 -04:00
Juan Denis 31dd984970 Add bulk container stats and UI workspace revamp
Backend: add POST /docker/containers/stats and DockerService.get_containers_stats to fetch resource metrics for multiple containers in a single docker stats call (parses JSON lines and returns a map keyed by ID/Name). Validates input and logs errors.

Frontend: refactor Docker page into a two-column workspace with a left sidebar for targets, resources and maintenance, and a main area with workbar and panel. Add support for multiple targets (default local), fetch available servers, and expose selection UI. Implement bulk stats fetching via api.getContainersStats for local hosts, periodic refresh, per-container stats caching, sorting controls for the container list (status/name/image/cpu/memory/created), and improvements to the container inspector (drawer behavior, loading timer, close action). Update API client with getContainersStats and adjust container stats parsing to handle multiple shapes.

Styles: add comprehensive SCSS for the new workspace, sidebar, inspector drawer, inventory and sort control, and responsive behavior.
2026-05-03 06:12:39 -04:00
Juan Denis 85fb3b5bb6 Add compose list API and overhaul Docker UI
Add backend support for listing Docker Compose projects: new /docker/compose/list endpoint and DockerService.compose_list with a JSON-parsing path and a fallback that builds projects from container labels for older compose binaries. Fix RemoteDockerService to use DockerService.get_container for remote/local inspection. Large frontend updates: DashboardLayout supports full-page routes; Databases page received a visual refresh with engine status badges and a summary grid; Docker page refactored extensively — normalize container fields, consistent ID/name/image helpers, table-based resource list, inspector sidebar (ports/mounts/env), resource bars, improved logs/exec handling, and disabled actions for remote targets. Compose tab now uses the new compose list API and streamlines compose actions. File Manager now keeps current path in the URL (search params), tracks previous target changes, and manages selection state more robustly. Miscellaneous UX fixes and icon updates across pages.
2026-05-03 05:10:01 -04:00
Juan Denis b4414aa5b8 Introduce unified dev launcher and SCSS migration
Add a unified, cross-platform development launcher and update docs/styles to SCSS.

- Add dev/dev.sh: comprehensive Bash dev launcher with stable non-default ports, port resolution/cleanup, WSL-aware behavior, ngrok support, and validation tooling.
- Rewrite Windows entrypoint (dev.ps1) to require WSL and delegate to dev/dev.sh; make top-level dev.sh a thin wrapper that execs dev/dev.sh.
- Add AGENTS.md with project overview, architecture, and development instructions for assistance tools.
- Update docs (CLAUDE.md, CONTRIBUTING.md) to reflect migration from LESS to SCSS and update style guidance.
- Update .gitignore to ignore backend/.venv-wsl, frontend.env.development.local, and /.agents.
- Frontend: add new pages and page-specific SCSS files, update main.scss, components, pages, client/socket services, and vite.config.js to support the SCSS-based frontend changes.

These changes unify local development workflows (especially via WSL), improve port stability, and complete the frontend styling migration from LESS to SCSS.
2026-05-03 04:20:14 -04:00
Juan Denis a79bbc27f7 Add connstring, file handlers, and security tests
Introduce connstring package and tests to decode panel "connection strings" and add UI/CLI hooks to accept them. Move file access handlers into a dedicated file_handlers.go with strict allowlist checks that resolve symlinks and validate parent dirs to prevent escapes; add unit tests covering symlink and allowlist behaviour. Add credential-rotation HMAC verification, command blocking and configurable exec timeout resolution, gate system:exec registration by feature flag, and fix Docker logs reading to use io.ReadAll with a size cap. Misc: buffer restart channel to avoid IPC hangs, improve UDP discovery error handling, expose IPC token via a local endpoint and add IPCTokenPath, and wire the pairer to handle connection-string pairing and persist credentials. Overall changes focus on security hardening, UX for single-string pairing, and reliability fixes.
2026-05-02 00:51:47 -04:00