Skip to content

Drift doctor, migration imports, database tools, security suite and hosting polish#58

Merged
jhd3197 merged 50 commits into
mainfrom
dev
Jul 4, 2026
Merged

Drift doctor, migration imports, database tools, security suite and hosting polish#58
jhd3197 merged 50 commits into
mainfrom
dev

Conversation

@jhd3197

@jhd3197 jhd3197 commented Jul 4, 2026

Copy link
Copy Markdown
Owner

This is the big "make the panel earn its keep" drop. It started as a marketplace cleanup and turned into a whole shelf of operator features — the kind of things you only miss the day you actually need them. The headline is a config-drift doctor that re-renders every managed resource from panel state, diffs it against what's on disk, and offers diff-confirmed repair without ever touching anything automatically. Around that sit a full migration pipeline (cPanel/DirectAdmin/Hestia archives and live-site pulls over SSH), a set of real database tools, a security suite (web-shell YARA scans, file-integrity monitoring, a cloud-metadata egress guard), and a batch of hosting quick-wins. Then two more headliners landed on top: a mail hosting extension that runs a full mail server (SMTP/IMAP/JMAP) per domain — with a preflight gate that refuses to let you send until PTR, outbound port 25 and blocklist checks actually pass — and serverkit.yaml, a declarative manifest that describes a whole multi-service project in one file the panel can scaffold, apply, re-sync on push and drift-check like everything else. Everything destructive stays opt-in and diff-confirmed, and the whole thing is backed by ~30 new test suites. The marketplace also finally collapsed into a clean two-tab store.

Highlights

  • Doctor + drift detection — a daily read-only sweep flags when a managed nginx vhost or compose override no longer matches panel state; a new Doctor tab on Monitoring diagnoses drift, core services, cert expiry, disk headroom and databases, with per-item and batch repair you confirm from a diff.
  • Import a whole site — a 5-step wizard at /imports restores cPanel/WHM, DirectAdmin and Hestia/Vesta backup archives (domains, databases, DB users, cron) as managed apps, plus a separate "pull a live WordPress site over SSH" flow that dumps the DB through the tunnel and rebuilds it with the URL rewritten.
  • .htaccess → nginx converter — paste your old rewrite/redirect/auth rules and get nginx directives back, with anything untranslatable flagged by reason and line.
  • Database tools — a live processlist with kill, a RAM-aware config tuner (suggested-not-applied, with backups and rollback), first-class managed database users, and one-click "Open in Adminer" SSO via a single-use 5-minute shadow credential.
  • Security suite — job-backed malware scans with a curated web-shell YARA pass (and a pure-Python fallback), scoped file-integrity monitoring, and a default-on egress guard that blocks app containers from the 169.254.169.254 cloud-metadata endpoint.
  • Mail hosting — a new built-in extension runs a managed mail server per domain (SMTP/IMAP/JMAP with mailboxes and aliases), auto-plants MX/SPF/DKIM/DMARC records through your existing DNS connections, and gates outbound sending behind a preflight that verifies PTR, port-25 reachability and blocklist status before a single message leaves.
  • Describe your stack in one file — a serverkit.yaml manifest declares services, databases, domains, env and health checks for a whole project; the panel scaffolds it, shows a plan, applies it, re-syncs it on every git push and flags drift when reality wanders — with fromSecret/fromService/generate references so credentials never live in the file.
  • Two new extensions — a CrowdSec integration (decisions, alerts, ban/unban via cscli) and an authoritative DNS server (managed PowerDNS with zones, records, DNSSEC and a delegation check) for homelab/air-gapped setups.
  • Hosting quick-wins — per-domain bandwidth accounting with sparklines, an opt-in per-site nginx micro-cache with safe cookie/path bypasses, and first-class per-app CPU/memory limits with live usage.
  • Operator conveniences — an API-backed serverkit CLI (status, doctor, repair, support-bundle, login-url…), a sanitized diagnostic support bundle, one-time login links, and a demo mode that blocks all mutations.
  • Marketplace, tidied — Browse + Installed, one row per extension with a Built-in/Registry/Manual source badge and the full action set; manual install moved into a modal; registry defaults to the public serverkit-extensions index.
Technical changes

Drift / doctor

  • drift_service.py re-renders the expected nginx vhost and compose override for each managed resource and diffs against disk; doctor_service.py runs the full sweep (drift, core services, cert expiry, disk, DB) and drives per-resource repair. doctor_bp at /api/v1/doctor; daily job registered via DriftService.register_jobs()/DoctorService.register_jobs(). Repairs are always diff-confirmed, never automatic.

Migration imports

  • site_import_service.py + site_importers/{base,cpanel,directadmin,hestia}.py analyze an archive into a report then run a resumable, retry-from-failed-step job that maps it to an app, managed databases (preserving MySQL password hashes where the engine allows) and cron. site_imports_bp at /api/v1/imports; SiteImport model + migration 051. Upload and fetch-by-URL paths both carry SSRF and archive-traversal guards.
  • WordPress SSH import (serverkit-wordpress/backend/wp_ssh_import_service.py) probes for a pinned host key and site facts, then pulls docroot + DB dump over the tunnel and rebuilds with a URL search-replace.
  • htaccess_converter.py translates rewrite/redirect/auth/access rules to nginx, reporting untranslatable rules with reason + line; exposed via htaccess_tools_bp under /api/v1/apps.

Database tools

  • db_process_service.py (processlist + kill, server or container), db_config_tuner_service.py (curated RAM-aware suggestions applied with backup/rollback, never auto-applied), managed_db_user_service.py + ManagedDatabaseUser model (migration 050), and db_admin_sso_service.py (single-use 5-minute shadow credential scoped to one database, Adminer SSO). Blueprints: managed_db_users_bp, db_tuner_bp.

Security

  • yara_scan_service.py + yara_rules/webshells.yar (eval/base64 droppers, c99/r57/WSO markers, PHP-in-image, auto_prepend hijacks) with a pure-Python fallback when yara is absent, custom-rule upload, and quarantine/restore; malware scans moved onto the job bus and can target an app docroot.
  • file_integrity_service.py baselines and diffs ServerKit-managed paths on a 6-hour job, feeding the Notifications Bus; baseline/check/accept controls on Security → Integrity.
  • metadata_guard_service.py installs a default-on (opt-out) firewall rule blocking 169.254.169.254 from app containers; MetadataGuardService.register_jobs(). Additions in security_service.py / firewall.py / security.py.

Extensions

  • serverkit-crowdseccrowdsec_service.py wraps cscli for decisions/alerts/ban/unban/allowlists with graceful degradation; CrowdSecPage.jsx.
  • serverkit-dns-serverdns_server_service.py runs PowerDNS in a managed container (zones, records, DNSSEC + DS records, delegation check); DnsServerPage.jsx / ZoneDetail.jsx. Both shipped in builtin-extensions/ and pre-bundled into frontend/src/plugins/.
  • serverkit-mail — Stalwart-backed mail hosting on the same managed-container pattern: stalwart_service.py drives the engine over its admin API (pinned against live 0.16.11), mail_service.py + models.py own the ext_serverkit_mail_* tables (domains, mailboxes, aliases), dns_mail_service.py plants MX/SPF/DKIM/DMARC through existing DNS connections, and preflight_service.py hard-gates sending (409) until PTR, outbound port 25 and RBL checks pass. mail_jail_service.py and mail_backup.py reuse the Fail2ban and backup rails; MailPage.jsx is a tab-group UI. Two proving suites cover the extension and the preflight/DNS path.

serverkit.yaml manifests

  • manifest_spec_service.py defines the v1 spec + normalizer (schema in docs/serverkit-yaml.schema.json, guide in docs/SERVERKIT_YAML.md); manifest_scaffold_service.py generates a starter manifest from an existing app.
  • manifest_persistence_service.py + ApplicationManifest model (migrations 054/055) persist the parsed manifest, seed env vars and gate deploys on declared health checks.
  • manifest_apply_service.py is the resolve → plan → apply engine; domain_attach_service.py gives core a first-class domain-attach path; env_reference_service.py resolves fromSecret/fromService/generate binders so secrets never sit in the YAML.
  • manifest_sync_service.py re-syncs on git push and adds a manifest drift-check family + events; manifest_preview_service.py powers manifest-driven PR previews; cli.py gains manifest verbs and manifests_bp exposes it all under /api/v1.
  • Frontend: wizard summary step in NewService.jsx, a Manifest section in the service SettingsTab.jsx, a project status strip in ProjectDetail.jsx, and services/api/manifests.js.

Hosting

  • bandwidth_service.py aggregates nginx access logs into per-site daily transfer stats (SiteBandwidth model, migration 052); bandwidth_bp at /api/v1/bandwidth, sparklines on the Services list.
  • Per-site micro-cache in nginx_service.py (10s TTL, bypass on logged-in/admin/cart cookies + paths, X-SK-Cache header, manual purge; migration 053).
  • Per-app CPU/memory limits: application.py model fields (migration 048), applied in docker_service.py without editing the user's compose file; ResourceLimitsPanel.jsx.

Operator / auth

  • cli.py + cli_api_client.py back the serverkit CLI verbs against the API with a break-glass 10-minute in-process token (audit-logged); support_bundle_service.py exports a secret-scrubbed diagnostic zip (support_bundle_bp).
  • login_link_service.py + LoginLink model (migration 049) mint single-use, short-TTL, optionally IP-bound login URLs, hashed at rest and reaped hourly; auth.py + LoginLinksSection.jsx.
  • middleware/demo.py blocks mutating calls with 403 demo_mode and seeds read-only demo credentials.
  • speed_test_service.py on-demand download/upload/latency test (Ookla CLI with pure-Python fallback); speedtest_bp.

Marketplace

  • Browse/Installed two-tab store; Installed lists all built-in/registry/manual extensions with source badges and full actions; registry installs stamped source_type='registry' (plugin_service.py, registry_service.py); ManualInstallModal.jsx off the topbar; registry defaults to the public serverkit-extensions index.

Misc

  • DNS provider routes moved back into core (api/dns_providers.py) so provider connections don't depend on an extension; the frontend's fallback API error now names the endpoint and status (services/api/client.js).
  • python-socketio bumped to 5.16.3 and python-engineio to 4.13.3 to clear three DoS advisories flagged by the dependency scan.
  • New frontend services/api/* modules for every feature above, App.jsx routes, OverviewTab/SettingsTab wiring, and utility helpers (formatBytes, expiry, sanitizeSvg, clipboard). CHANGELOG + README updated; VERSION bumped to 1.7.16. ~30 new backend test suites cover imports, drift/doctor, YARA, file-integrity, metadata guard, DB tools, bandwidth, micro-cache, CLI, login links, demo mode, the manifest engine and all three new extensions.

jhd3197 and others added 29 commits July 3, 2026 03:57
…sions index

SERVERKIT_REGISTRY_URL unset now resolves to the curated raw index at
jhd3197/serverkit-extensions (the go-live step for the registry infra);
set-but-empty explicitly disables remote fetching (air-gapped panels,
and how the test suite stays offline — pinned in conftest). URL is
resolved per fetch so env changes apply without a restart. Cache ->
bundled fallback chain unchanged; the Marketplace never blanks.

3 proving tests (default, empty-disables, override); registry/plugin
selection 76 passed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>
…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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
… 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>
…ver, 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>
Copilot AI review requested due to automatic review settings July 4, 2026 02:35

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot wasn't able to review this pull request because it exceeds the maximum number of lines (20,000). Try reducing the number of changed lines and requesting a review from Copilot again.

jhd3197 and others added 21 commits July 3, 2026 23:18
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>
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>
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>
- 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>
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>
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>
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>
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>
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>
…e 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>
…h (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>
…ase 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>
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>
… (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>
…p (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>
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>
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>
@jhd3197 jhd3197 merged commit 578b034 into main Jul 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