Commit Graph
1154 Commits
Author SHA1 Message Date
Juan DenisandClaude Opus 4.8 98d05eecdf fix(recovery): gpu core-slim move + cross-service doctor/schedule wiring
Cluster G of plan 38 (plan 32) + integration glue.

- gpu: complete the core-slim move — remove core app.api.gpu +
  app.services.gpu_service (+ its blueprint registration), rebuild the probe in
  the serverkit-gpu builtin extension (nvidia-smi parser, Linux-guarded)
- __init__: register dns_cutover + setup_health blueprints
- doctor_service: add fleet DNS-vs-IP checks, backup-proof checks
  (backup_drill_stale/backup_unverified), and the setup-health section into run()
- builtin_handlers: seed the host-doctor sweep + weekly setup-health nag
- test_jobs: schedule count 15 -> 17 for the two restored schedules

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 01:41:54 -04:00
Juan DenisandClaude Opus 4.8 b29fa77313 fix(recovery): rebuild authz-R2 policy + notification digests/chat webhooks
Clusters E+H of plan 38 (plans 24/29/33).

- security_policy_service: require-2FA policy (ok/nudge/enforce), SSO-exempt,
  grace window (plan 29); restored can_operate_app/can_admin_app on
  resource_grant_service for the member-action callers — 23 tests green
- notifications/digest: per-user daily/weekly digest rollups over queued_digest
  deliveries, respecting cadence + last_sent_at (plans 24/33)
- notifications/service: deep-link action_path/action_label on send + inbox
  category/severity filters (plan 24 Phase 5); catalog link builder
- chat_webhook_service: org chat/webhook connections, HMAC-signed delivery,
  category fan-out through the notify bus (plan 33)
- restored digest_cadence/digest_last_sent_at on NotificationPreferences

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 01:41:43 -04:00
Juan DenisandClaude Opus 4.8 7a903edc4f fix(recovery): rebuild setup-health/reconcile + backup drill/verify services
Clusters B+D of plan 38 (plans 22/30).

- setup_health_service: scored setup-health item registry, per-user snoozes
  (users.setup_snoozes), nag job, doctor_checks() (plan 22)
- setup_reconcile_service: DNS backfill + URL-fix preview/apply jobs (plan 22)
- backup_drill_service: expectation-stamped restore drills, container-aware DB
  legs, real WordPress DB leg, enqueue-time single-flight, vacuous-drill
  detection (plan 30) — reconstructed from surviving drill tests
- backup_verify_service: manifest write/read + tier-1 verify ladder, consumed by
  backup_offsite_service
- backup_policy_service: restore-proof badge (_restore_proof_view) in the policy
  view (plan 30)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 01:41:31 -04:00
Juan DenisandClaude Opus 4.8 a131cf5e0f fix(recovery): rebuild DNS cutover service+API and SSH site importer
Cluster C of plan 38 (plan 31). dns_cutover_service reconstructed from readable
string fragments + plan doc + the frontend contract; SSH importer from the
surviving wiring tests.

- dns_cutover_service: server-sourced snapshots, dry-run + real cutover via the
  guarded provider client, world-restoring revert that deletes cutover-created
  records (uses restored DnsCutoverSnapshot) — 20 tests green
- api/dns_cutover: 7 JWT/admin-gated endpoints matching dnsCutover.js
- site_importers/ssh: GenericSshImporter + parse_ssh_source, keyfile-only,
  credential-scrubbing; wired into site_import_service ('ssh' source) — 33 tests

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 01:41:22 -04:00
Juan DenisandClaude Opus 4.8 7b8e604fab fix(recovery): rebuild agent-fleet survey + fleet doctor/repair services
Cluster A of plan 38 (plans 27/28). survey_service reconstructed from the
surviving test + api/survey.py caller (bytecode corrupt); fleet_repair_service
recovered faithfully from readable bytecode; fleet_doctor_service reconstructed
from the fleet contract + FleetDoctorResult model (bytecode corrupt).

- survey_service: probe catalog, run_survey/normalize_map/diff_maps over the
  agent registry, ServerSurvey snapshots (6 tests green)
- fleet_doctor_service: allowlisted fleet health sweep writing one
  FleetDoctorResult per (server_id, check_key) + DNS-vs-IP checks
- fleet_repair_service: executes the doctor's allowlisted repair actions
  (audited, capability-gated) — 20 proving tests green

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 01:41:13 -04:00
Juan DenisandClaude Opus 4.8 64508c5f39 fix(recovery): rebuild lost frontend components + recover corrupted files
Phase 3 of the recovery rebuild (plan 38). `npm run build` green again.

Reconstructed feature components (plans 20/21/25/27/31/32):
- ExtensionBoundary.jsx, serverkit-gpu/GpuMonitor.jsx — recovered clean from
  the D: backup verbatim
- ds/KpiBand.jsx (+ SCSS) — rebuilt from plan 20 + importer call-sites
- SchedulePicker.jsx — cron picker rebuilt against ScheduleCard + existing SCSS
- pages/Coexistence.jsx — adoption/observed-server page (PageTopbar)

Recovered 5 pre-existing corrupted files (content had been overwritten with
unrelated log/JSON data in an earlier recovery, committed to history):
- WorkspaceSwitcher.jsx, _shared-resources.scss — spliced (real content
  survived; garbage tail truncated)
- Jobs.jsx, Email.jsx, _backups.scss — reconstructed from ApiService contracts
  + surviving markup (functional; noted as reconstructions in-file)

Gate: npm run lint (0 errors) && npm run build (built, 3058 modules) both pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 01:02:29 -04:00
Juan DenisandClaude Opus 4.8 ce97d75d60 fix(recovery): restore models + migration chain 056-074, cron_run_service, rbac authz
Phase 1 of the July-5-7 recovery rebuild (plan 38). Backend now boots.

- models: reconstruct DnsCutoverSnapshot (from bytecode) + FleetDoctorResult
  (from migration 063 DDL); restore lost columns applications.ports/
  bootstrap_done, app_volumes.declared_size, dns_provider_configs.origin_ca_key
- migrations: recreate the 15 missing revisions 056/057/060/062/063/064/065/
  067/068/069/070-074, reconciling the chain to a single linear head (074).
  add_column revisions guard on live schema so a fresh-DB upgrade reaches head
- rbac: restore _APP_ROLE_RANK + require_workspace_access/require_workspace_role/
  app_access_tier/require_app_member (plan 19/29 4-tier authz), recovered from
  bytecode; unblocks api/cron.py import
- services: reconstruct cron_run_service.CronRunService (record_run/recent_runs/
  stats, edge-triggered failure/recovery transitions) from bytecode

Gate: create_app() imports clean, db.create_all() OK, flask db upgrade on a
fresh SQLite DB reaches head 074 (linear chain).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 00:17:55 -04:00
github-actions[bot] 65fa3e11e3 chore: bump version to 1.7.17 [skip ci] 2026-07-08 01:05:33 +00:00
Juan Denis a2e92535ec chore: gitignore the Vite dep-cache (.vite/) so it never gets committed 2026-07-07 21:04:59 -04:00
Juan Denis d8bfb5cf41 docs: recovery record + recovered original commit messages 2026-07-07 20:32:54 -04:00
Juan Denis 0a4f5bcc25 fix(staging): restore uncorrupted test_stage.sh (recovery artifact was NUL-corrupt) 2026-07-07 20:31:26 -04:00
Juan Denis 6e32519f7e restore: remaining reconstructed July 5-7 changes (clean recovered files not attributable to one plan) 2026-07-07 20:29:31 -04:00
Juan Denis e08fe94b21 feat(staging): plan 37 testbed — stage.sh/stage-remote.sh, STAGING banner+health, profiles, tests 2026-07-07 20:29:31 -04:00
Juan Denis 28129e7848 feat(cloudflare): round 2 — DNSSEC, Origin CA, rules, R2 preset (plan 36) 2026-07-07 20:29:31 -04:00
Juan Denis 59e92c64a6 feat(manifest): appliance tier — ports/volumes/multi-container units (plan 35) 2026-07-07 20:29:30 -04:00
Juan Denis 38c281d274 feat(cron): completion — run history, project scope, cwd/run-as (plan 34) 2026-07-07 20:29:29 -04:00
Juan Denis 45942339eb feat(notifications): polish — digests, prefs, deep-links (plans 24/33) 2026-07-07 20:29:29 -04:00
Juan Denis c96a476a74 feat(extensions): runtime-frontend hardening + GPU core-slim (plan 32) 2026-07-07 20:29:28 -04:00
Juan Denis a882d35db9 feat(adoption): DNS cutover+verify, snapshots, SSH import (plan 31) 2026-07-07 20:29:26 -04:00
Juan Denis 7d045f32af feat(backup): trust round 2 — restore drills, offsite/verify (plan 30) 2026-07-07 20:29:25 -04:00
Juan Denis 6b6237bc17 feat(security): authz hardening round 2 (plan 29) 2026-07-07 20:29:24 -04:00
Juan Denis 44892d3314 feat(agent): V2 capability pack — survey/doctor/fleet sweep+repair (plan 28) 2026-07-07 20:29:24 -04:00
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