Commit Graph
1132 Commits
Author SHA1 Message Date
Juan Denis 2eabfac2b8 feat(onboarding): setup health, preflight + reconcile (plan 22) 2026-07-07 20:29:23 -04:00
Juan Denis 782ea70c8b feat(workspace): scoping audit + per-scope matrix (plan 19) 2026-07-07 20:29:22 -04:00
github-actions[bot] 07baefb53f chore: bump version to 1.7.16 [skip ci] 2026-07-04 07:07:44 +00:00
Juan DenisandClaude Fable 5 9e68202fae fix(deps): bump python-socketio to 5.16.3 and python-engineio to 4.13.3
Resolves Safety scan DoS advisories SFTY-20260626-04169 (socketio) and
SFTY-20260626-60054 / SFTY-20260626-39072 (engineio). Verified compatible
with Flask-SocketIO 5.6.1 under async_mode='threading'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 02:49:48 -04:00
github-actions[bot] 79bd032a09 chore: bump version to 1.7.15 [skip ci] 2026-07-04 06:07:22 +00:00
Juan Denis 3c34bd64db Merge branch 'dev' of https://github.com/jhd3197/ServerKit into dev 2026-07-04 02:05:32 -04:00
Juan DenisandClaude Opus 4.8 0fef6825c6 chore(plugins): re-sync bundled serverkit-mail plugin.json
Regenerate the pre-bundled frontend/src/plugins copy from its
builtin-extensions source (node scripts/sync-builtin-frontends.mjs) to clear the
builtin-frontend drift CI check. Content-identical re-serialization; no
behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 02:03:37 -04:00
github-actions[bot] 5fe5473ba0 chore: bump version to 1.7.14 [skip ci] 2026-07-04 06:01:54 +00:00
Juan DenisandClaude Opus 4.8 57ca8617da feat(manifest): wizard summary, Settings section, project status strip (Phase 5 frontend)
Add manifest UI: the repo-import wizard shows a multi-service summary when a
version:1 serverkit.yaml is detected; Service detail Settings gains a Manifest
section (managed-by badge, status pill, scaffold download, Plan/Apply); the
project view shows a manifest status strip. New api/manifests.js client module.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 01:49:07 -04:00
Juan DenisandClaude Opus 4.8 e1f9d5bb7a feat(manifest): fleet targeting, manifest-powered previews, CLI verbs (Phase 5 backend)
Route manifest-created apps to a fleet server via top-level/per-service server:
(sets Application.server_id; unknown server = plan issue). Clone the
manifest-resolved config (env + per-preview overrides + domain) into non-WP PR
previews via ManifestPreviewService. Add 'serverkit manifest plan|apply|diff'
CLI verbs against the manifests API.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 01:46:34 -04:00
Juan DenisandClaude Opus 4.8 8d61abbf2c feat(manifest): push re-sync, drift check family, events (Phase 4)
Both webhook receivers now re-read serverkit.yaml after a deploy: unchanged hash
is a no-op, a changed manifest auto-applies its autoDeploy services and flips the
rest to pending with an admin notification. Register a 'manifest' drift check
that projects live state onto the declared surface (in_sync iff declared items
match; repair re-applies). Emit manifest.applied/pending/drifted/error events.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 01:39:53 -04:00
Juan DenisandClaude Opus 4.8 f823c6c74f feat(manifest): fromSecret/fromService/generate reference binders (Phase 3)
Add EnvironmentVariable.value_from (migration 055) so an env var can resolve from
a vault secret or a sibling service's connection property at injection time — the
value never lands in the row, masking stays intact, and a rotated secret
propagates on next deploy. EnvReferenceResolver handles both; the apply engine
plans set_env_ref steps, flags missing secrets as plan-time issues, and generates
a random vault secret for generate:true (idempotently).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 01:34:54 -04:00
Juan DenisandClaude Opus 4.8 315c80e9a0 feat(manifest): apply engine — resolve/plan/apply + core domain attach (Phase 2)
Add manifest_apply_service (resolve -> ordered plan -> idempotent apply inside a
manifest.apply DeploymentJob with before/after snapshots), covering app create/
update, env, volumes, managed databases, backup policies and domain attach.
Extract the WordPress one-call domain+SSL pattern into a core DomainAttachService
(DNS -> vhost -> best-effort cert, each stage degrading to a warning). Wire the
/api/v1/manifests blueprint with get/plan/apply (admin-gated, audit-logged).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 01:28:16 -04:00
Juan DenisandClaude Opus 4.8 ae0f823e90 feat(manifest): persist manifest + seed env + health-check gate (Phase 1)
Stop dropping what import already detects. Add Application.healthcheck_path
(migration 054) and an application_manifests table (one row per project) storing
the normalized manifest, hash and provenance. Import now seeds non-secret env
values and records the health-check path, and the zero-downtime restart gate
polls that path instead of a blind sleep.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 01:16:29 -04:00
Juan DenisandClaude Opus 4.8 8c5ede0cfd feat(manifest): v1 serverkit.yaml spec, normalizer, scaffold (Phase 0)
Add the declarative serverkit.yaml v1 spec: JSON Schema + reference doc, a pure
parse/validate/normalize service, version:1 recognition in the repo manifest
detector (legacy flat files unchanged), and a scaffold endpoint that renders a
manifest from a live app.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 01:11:50 -04:00
Juan DenisandClaude Opus 4.8 f3a1f09b6e docs(mail): record live Stalwart 0.16 findings from real-box validation
Validated the engine against a real public box (DO, port-25 egress open) in
addition to WSL. Documents two findings for the next iteration:
- setup can be completed programmatically: in bootstrap GET /api/account grants
  sysBootstrapGet/sysBootstrapUpdate, so the panel could auto-finish Stalwart's
  one-time setup rather than requiring the web wizard
- the management vocabulary (principal/dkim/queue/mailbox/domain) was confirmed
  against Stalwart's own config schema, so the EP_* nouns are correct

No behavior change — comment only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 00:56:52 -04:00
Juan DenisandClaude Opus 4.8 427492cb4b fix(mail): pin Stalwart engine against live 0.16.11 (WSL+Docker)
Ran the real container and drove its API; corrected what only a live box
reveals:

- image is stalwartlabs/stalwart:latest — the assumed stalwartlabs/mail-server
  no longer resolves on Docker Hub (404 on pull)
- config lives at /etc/stalwart/config.json and data at /opt/stalwart, so
  install() now bind-mounts two host dirs instead of one /opt/stalwart-mail
- admin credential is pinned via a single STALWART_RECOVERY_ADMIN=user:secret
  env var (not FALLBACK_ADMIN_USER/SECRET)
- a fresh container boots into BOOTSTRAP mode: only the /account setup UI is up
  and every /api/* returns 404 (RFC-7807 problem+json) until the one-time setup
  completes. get_status now probes /api/session and reports needs_setup +
  setup_url; the Overview UI shows a "finish setup" banner. Verified live:
  GET /api/session -> 404 problem+json.
- _api parses the problem+json detail/title error shape

Tests updated to the real install argv + two new cases (bootstrap needs_setup,
problem+json parsing): 58 pass. Post-setup CRUD sub-paths (/api/principal etc.)
remain best-effort constants until confirmed against a fully-initialized
instance on a real box.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 00:48:01 -04:00
Juan DenisandClaude Opus 4.8 d99d4db6a9 test(mail): proving suite for serverkit-mail + changelog
56 hermetic tests (docker/HTTP/socket/DNS-provider all stubbed; pass on
Windows). Cover: manifest validity + lifecycle-key/jobs wiring (guards the
loader-key bug), models + no mailbox-password column, Stalwart install argv
(admin API loopback-only, mail ports, generated+persisted admin secret) and
Windows gating, preflight pass/block + persistence, the sending-activation
gate (refused without a passing preflight, force override audited), DKIM
keygen + exact SPF/DKIM/DMARC/MX/A record push with source='mail', fail2ban
jail, and blueprint auth/validation/503 paths.

CHANGELOG: document the Mail Server extension under Unreleased.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 00:27:41 -04:00
Juan DenisandClaude Opus 4.8 d0d55fc2ea feat(mail): serverkit-mail frontend tab-group UI
Self-contained multi-tab Mail Server page mirroring the serverkit-dns-server
plugin shape (named MailPage export, no default export; own PageTopbar tabs;
generic api.request calls). Tabs: Overview (status/install/service + a
prominent deliverability preflight banner that makes clear sending is blocked
until PTR/port-25/RBL pass), Domains, Mailboxes (+ autoresponder), Forwarders,
DNS & DKIM (generate/deploy records + copy-to-clipboard + LE cert), Queue.

Canonical source under builtin-extensions/serverkit-mail/frontend/ with a
byte-identical synced copy (+ manifest) under frontend/src/plugins/serverkit-mail/.
SCSS-only, host components reused, no inline styles. Verified: eslint 0 errors,
npm run build succeeds (Vite compiles the plugin).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 00:27:39 -04:00
Juan DenisandClaude Opus 4.8 f428ac10e3 fix(mail): correct lifecycle manifest keys and status version probe
- plugin.json: lifecycle hooks were keyed on_install/on_uninstall, but the
  loader reads lifecycle.get('install')/('uninstall') — the hooks (notify-event
  registration, container teardown) would have silently never fired. The
  manifest validator only vets the values, not the keys, so this slipped past.
- stalwart_service.get_status: read the engine version from a dedicated
  read-only /status endpoint instead of GET-ing the /reload endpoint.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 00:27:25 -04:00
Juan DenisandClaude Opus 4.8 2f36fa4c92 feat(mail): serverkit-mail extension backend (Stalwart engine)
New opt-in builtin mail-hosting extension driven by a Stalwart mail-server
container via its HTTP admin API. Mirrors the serverkit-dns-server shape
(Docker + API choke-points, Linux/Docker best-effort gating).

- models.py: ext_serverkit_mail_* tables (domains, mailboxes, forwarders,
  autoresponders, preflight) via models:register; mailbox passwords never stored
- stalwart_service.py: engine — _docker/_api choke-points, install/status/
  uninstall/control, best-effort account/domain/queue reconcile
- mail_service.py: DB<->Stalwart orchestration; sending activation blocked
  until preflight passes (force override is audit-logged)
- preflight_service.py: blocking PTR / port-25 egress / RBL / listening-port
  checks; Windows/dev returns skipped, never raises
- dns_mail_service.py: DKIM RSA-2048 keygen + SPF/DMARC/MX/A push via
  DNSProviderService (source='mail') + LE cert best-effort
- mail_jail_service.py: fail2ban serverkit-mail-* auth jail
- mail_backup.py: registers maildir as a BackupPolicy files-target
- jobs.py/lifecycle.py: daily preflight re-check + notify events
- mail.py: /api/v1/mail blueprint (viewer/admin RBAC, {'error':msg} JSON)

Verified: production import path OK, manifest passes validator, 5 tables
create, 18 route rules register, DKIM/SPF/DMARC/MX/A record-building correct,
Windows-gating clean. No core files touched; not added to FLAGSHIP_SLUGS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 23:56:46 -04:00
Juan DenisandClaude Fable 5 df63abe74a fix(frontend): name endpoint and status in fallback API error
A missing route used to surface as a bare "Request failed" toast; now
it reads e.g. "Request failed (405): /api/v1/email/dns-providers" so
the broken endpoint is diagnosable from the UI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 23:18:14 -04:00
Juan DenisandClaude Fable 5 75a839f556 fix(dns): move DNS provider routes back to core
The /api/v1/email/dns-providers routes lived only in the serverkit-email
extension, so panels without it (email is gated to mail users) got a
404/405 from the Settings -> Connections DNS tiles. The service was
already core; the routes now are too, at the same historical paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 23:18:08 -04:00
github-actions[bot] 145d6b1506 chore: bump version to 1.7.13 [skip ci] 2026-07-04 02:23:40 +00:00
Juan Denis 03ede7b97a Merge branch 'dev' of https://github.com/jhd3197/ServerKit into dev 2026-07-03 22:23:19 -04:00
Juan DenisandClaude Fable 5 b35a41bfcc chore(plugins): sync pre-bundled builtin frontends (crowdsec, dns-server, wordpress)
Regenerated via scripts/sync-builtin-frontends.mjs; fixes the Extensions CI
drift check that failed after plan 15 added these extensions without
re-running the sync.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 22:18:50 -04:00
github-actions[bot] 6e9543047c chore: bump version to 1.7.12 [skip ci] 2026-07-04 02:00:18 +00:00
Juan DenisandClaude Fable 5 5e22aa8510 feat(panel): wire drift/doctor, CLI tools, security suite and hosting polish
Blueprint/model/job registrations and schedule seeding for drift,
doctor, support bundle, bandwidth, FIM, malware-scan and htaccess
tools; API module aggregation, SCSS imports and CHANGELOG for the
batch. Full backend suite: 1793 passed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 15:22:07 -04:00
Juan DenisandClaude Fable 5 e3b69da3c4 feat(extensions): authoritative DNS server extension
serverkit-dns-server runs PowerDNS (SQLite) in a managed container:
zones, records, DNSSEC with DS records for the registrar, and a
delegation check. Complements the provider integrations; for homelab
and air-gapped boxes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 15:22:07 -04:00
Juan DenisandClaude Fable 5 8ff893a4c8 feat(hosting): .htaccess to nginx converter
Paste-in translator for common rewrite/redirect/auth/access rules with
per-line unsupported flags, launched from the Import wizard (no core
custom-rules editor exists yet — output is copy/insert).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 15:22:05 -04:00
Juan DenisandClaude Fable 5 96d162e9a4 feat(hosting): per-site nginx micro-cache toggle
Opt-in 10s FastCGI/proxy micro-cache per site (migration 053) with safe
bypasses for logged-in/admin/cart cookies and paths, X-SK-Cache header
for verification, and a shared-zone purge. Flows through the drift-safe
vhost render seam so detection and writes always agree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 15:21:50 -04:00
Juan DenisandClaude Fable 5 3cbbcb5e6b feat(hosting): per-domain bandwidth accounting
Daily nginx access-log aggregation (migration 052) into per-site
transfer stats with 30-day sparklines on the Services list and a
monthly figure on the service Overview. Streaming parser handles
combined and vhost-prefixed formats plus rotation spillover.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 15:21:48 -04:00
Juan DenisandClaude Fable 5 ce6d0b11fb feat(extensions): CrowdSec integration extension
serverkit-crowdsec surfaces decisions/alerts, ban/unban and allowlists
via cscli with feature detection and graceful degradation when CrowdSec
is absent. Installs from Marketplace Browse; no core changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 15:21:36 -04:00
Juan DenisandClaude Fable 5 202b310c94 feat(security): scoped file-integrity monitoring
Baseline-and-diff over managed paths (nginx config, serverkit systemd
units, opt-in app docroots) on a six-hourly sweep, feeding the
Notifications Bus; Integrity tab gains baseline/check/accept controls
and a what-changed view.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 15:21:34 -04:00
Juan DenisandClaude Fable 5 c192e4f383 feat(security): job-backed malware scans with a web-shell YARA pass
Malware scans run as jobs and can target an app's docroot; a curated
web-shell rule set (yara CLI when present, pure-Python fallback) runs
alongside ClamAV with custom .yar upload; quarantine gains restore via
original-path metadata. Note: api/security.py also carries the FIM
routes of the next commit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 15:21:23 -04:00
Juan DenisandClaude Fable 5 c3f356b6fb feat(cli): API-backed operator verbs and diagnostic support bundle
serverkit status / services / apps / doctor [--repair] / repair /
update / login-url / support-bundle. Break-glass auth mints a 10-minute
admin JWT in-process (audit-logged) — root on the box already implies
full control. The support bundle exports a secret-scrubbed zip of
versions, service states, setting shapes and recent job failures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 15:21:22 -04:00
Juan DenisandClaude Fable 5 f296e1dd61 feat(ops): config drift detection, per-resource repair and doctor sweep
Daily read-only drift sweep re-renders expected nginx vhosts and compose
overrides from panel state (via extracted pure render seams) and diffs
against disk; drift notifies admins. Doctor tab on Monitoring runs the
full diagnosis (drift, services, certs, disk, DB) with diff-confirmed
per-item and batch repair. Nothing auto-repairs. The nginx render seam
also carries the micro-cache blocks used by the next commit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 15:21:09 -04:00
Juan DenisandClaude Fable 5 91e6f5cb29 feat(panel): wire imports, database tools and quick wins into the app
Blueprint/model/job registrations for the migration pipeline, speed
test, metadata guard, login-link + SSO reapers (seeded with the
builtin schedules), demo-mode middleware, /imports route, API module
aggregation and SCSS imports; CHANGELOG for the batch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 14:25:04 -04:00
Juan DenisandClaude Fable 5 64658cf91d feat(wordpress): pull-import a live site over SSH
Probe with host-key pinning, tar-stream the docroot, dump the DB
through the tunnel and rebuild via the existing import/URL-swap path;
3-step UI at /wordpress/ssh-import. Password auth needs sshpass;
secrets never hit argv or logs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 14:24:31 -04:00
Juan DenisandClaude Fable 5 d01d82036b feat(imports): panel-migration pipeline with cPanel, DirectAdmin and Hestia importers
Format-pluggable analyse->plan->run pipeline (migration 051) that maps
legacy panel backups to ServerKit apps, managed DBs (preserving MySQL
password hashes where portable) and cron entries, as resumable jobs
with per-step logs, SSRF/tar-traversal guards, and a 5-step Import a
Site wizard at /imports.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 14:24:29 -04:00
Juan DenisandClaude Fable 5 76a688fb49 feat(databases): managed DB users and one-click Adminer SSO
managed_database_users rows (migration 050) track users/grants so they
survive restarts; SSO launches an on-demand Adminer container
pre-authenticated with a single-use, 5-minute shadow credential scoped
to one database, reaped on schedule. Also mounts the config tuner in
the explorer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 14:24:15 -04:00
Juan DenisandClaude Fable 5 1fb7b81c32 feat(databases): curated engine config tuner
Vetted MySQL/PostgreSQL settings with RAM-aware suggestions, applied
via a ServerKit-owned drop-in (MySQL) or ALTER SYSTEM (PostgreSQL) with
timestamped backups, verified restart and clean rollback. Never
auto-applies.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 14:24:03 -04:00
Juan DenisandClaude Fable 5 0a82873c83 feat(databases): live processlist with kill in the explorer
SHOW FULL PROCESSLIST / pg_stat_activity normalized per server or
container, with admin-only kill/terminate and 5s auto-refresh tabs in
the Database Explorer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 14:24:02 -04:00
Juan DenisandClaude Fable 5 bd7624130c feat(auth): one-time login links and demo mode
Single-use, short-TTL, optionally IP-bound login URLs (hash-at-rest,
migration 049, hourly reap job) minted from Settings > Users; plus a
config-gated demo mode that 403s mutating API calls and seeds read-only
credentials on the login page.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 14:23:50 -04:00
Juan DenisandClaude Fable 5 9edeb68f85 feat(apps): first-class per-app CPU/memory limits
cpu_limit/memory_limit on Application (migration 048), emitted into the
generated compose and the ServerKit override for live re-apply, with a
Resource Limits panel (usage vs limit) in Service Settings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 14:23:39 -04:00
Juan DenisandClaude Fable 5 e7e2de486f feat(monitoring): on-demand server speed test card
Job-backed speed test (Ookla/speedtest-cli when present, pure-Python
fallback) with download/upload/latency surfaced on the Monitoring
overview; last result persisted in settings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 14:23:29 -04:00
Juan DenisandClaude Fable 5 4c76d43cb7 feat(security): cloud-metadata egress guard for app containers
Default-on (opt-out) DOCKER-USER drop rule for 169.254.169.254 with an
nftables fallback, toggleable from Security > Firewall. Kills the
SSRF-to-cloud-IAM credential-theft class on cloud VPSes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 14:23:11 -04:00
Juan Denis fe9e924626 polish(marketplace): extension copy sweep, publisher filter chips, docs + screenshot 2026-07-03 04:20:53 -04:00
Juan Denis e65f4e2845 feat(marketplace): merge installed tabs and move manual install into a modal 2026-07-03 04:14:31 -04:00
Juan DenisandClaude Fable 5 53220e5782 fix(plugins): stamp source_type='registry' on registry installs
install_from_url/install_from_path gain a source_type override (default
unchanged: 'url'/'local'). install_registry_extension stamps 'registry';
update_plugin preserves builtin/local/upload rows and stamps 'registry'
for url/registry rows; builtin copy-installs and repairs now stamp
'builtin' instead of 'local'; boot repair re-downloads registry rows too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 04:12:58 -04:00