The vite 8 upgrade (dcf05d1) makes the frontend build require Node ^20.19.0 ||
>=22.12.0 — on anything older npm silently skips rolldown's native binary and
`npm run build` dies with a cryptic MODULE_NOT_FOUND. Servers that build the SPA
on-box (source install + every update) would break their next update. So:
- install.sh node_ready() now gates on the real vite 8 floor (was Node >=18) and
provisions NodeSource 22 LTS when the host Node is too old.
- update.sh gains _node_build_ok(): build_frontend_bundle refuses (returns 1 →
caller rolls back) and the Docker-host rebuild halts, both with an actionable
"upgrade Node" message instead of a rolldown stack trace.
- Dockerfile + CI (release, release-smoke, extensions, scripts-nightly) bumped
node 20 -> 22 so the shipped/pre-built bundle is built on a compatible Node.
Also fixes a pre-existing parity bug the operator caught: update.sh rendered the
systemd unit WITHOUT substituting @BIND_HOST@ (install.sh does), so an update
left the literal placeholder and gunicorn would fail to bind. update.sh now
substitutes it (loopback default, SERVERKIT_BIND_HOST override) like install.sh.
Tests: test_update.sh +3 (node-floor gate, build refusal on old Node,
@BIND_HOST@ substitution) — 48 passed / 0 failed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Install the guard the data loss taught us to want: code and its proving tests
died together, so the suite stayed green (2572->2209 passing) while whole
features silently vanished — nobody diffs a green number.
- backend/tests/BASELINE_COUNT (2475) + check_test_count.py: compares pytest's
collected count to the floor; CI (backend-ci.yml new step) fails if it drops.
Lowering the floor requires editing BASELINE_COUNT in the same commit, so a
silent test loss surfaces as a red X instead of a still-green suite. Verified:
passes at baseline, exits 1 on a simulated drop.
- CHANGELOG: document the recovery-parity restore (Cloudflare R2 engine,
email-bounce, DNS-cutover staging, survey routes, cron CSS, 18 test suites)
and the ratchet.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- PULL_REQUEST_TEMPLATE gains a scripts-only checklist condensing the
failure-semantics rules (guarded observations, no &&-tail returns,
capture-safe stdout, errexit-immune helpers, fresh-box loop policy,
proving test in the same commit)
- record the self-update channel decision in the bootstrap header:
keep fetching from main, gated by the update-e2e CI job, preserving
one-push-fixes-the-fleet
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The July 2 outage lived in update.sh's top-level run block — code the
unit matrix never executes. Close the blind spot:
- update-e2e (PR-gated): real install.sh on the runner VM, health
probe, then THIS branch's update.sh --force with self-update
disabled, re-probe; failure dumps /var/log/serverkit + journal
- scripts-nightly.yml: install from the built release tarball (proves
the offline path + shipped-venv relocation), and install latest
published release -> update to current checkout (carry-forward
regressions same-version --force runs can't catch)
- advisory (non-gating) shellcheck --enable=all on install.sh/update.sh
- unit steps now also run test_cli.sh + test_agent_install.sh in both
the ubuntu job and the 7-distro matrix
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The panel frontend is now served straight from nginx/sites-available/*
(static SPA at location /, plus /api + /socket.io proxy). A broken
directive there 502s the whole panel on a real box, and nothing parsed
these configs in CI.
Add scripts/test/test_nginx_conf.sh: stages each vhost (secure +
insecure) against a real nginx, recreating the absolute paths they
reference (a stand-in frontend/dist bundle, the serverkit-locations /
conf.d include dirs, certbot webroot) and a throwaway self-signed cert
for the TLS vhost, then runs `nginx -t`. Skips cleanly (exit 0) where
nginx/openssl/root aren't available, so it's safe on a dev laptop.
Wire it into the Scripts CI `shell` job after the unit suites (installs
nginx + openssl so the step actually runs). shellcheck-clean at warning
severity; bash -n clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Hardening plan §7. Catches distro-specific regressions before release.
- scripts/test/vm-update.sh: install → forced local update (full blue/green
deploy/migrate/switch/health) → re-run to confirm the "Already up to date"
version-gate. Same VM harness contract as vm-install.sh (log + status file).
- scripts/test/vm-uninstall.sh: install + seed data → default uninstall asserts
data preserved (DB snapshot in backups, /var/lib survives) → reinstall →
--purge asserts data removed. End-to-end proof of the unified uninstaller.
- scripts-ci.yml: now runs all three serverless suites (update+install+lib),
lints the new lib/ + test/ files (error severity) and keeps scripts/lib/*
warning-clean, and expands the cross-distro unit matrix to Ubuntu 22.04/24.04,
Debian 12, Rocky 9, AlmaLinux 9, Fedora 40, and openSUSE Leap 15.5.
- test_install.sh: +choose_pkg_manager graceful-failure case (7.4); a no-op
docker stub so the uninstall-matrix cases run where docker isn't installed.
- test_lib.sh: neutralize the ambient container=oci env var (RPM/SUSE images)
and force an empty PATH for the "no package manager" case — both bugs the new
matrix surfaced (the tests, not the code).
- README: fixed the stale Fedora box, documented the new VM scripts + suites.
Validated by running the exact CI container logic locally across all seven
images: test_update 13/13, test_install 15-16/0, test_lib 13/13 everywhere.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The updater's logic had zero test coverage on any distro, and ServerKit
targets several Linux families — so a portability regression only ever showed
up on a server. Add a matrix job that runs bash -n + scripts/test/test_update.sh
inside debian:12 and rockylinux:9 containers (Ubuntu is already covered by the
lint job). Verified locally: 9/9 pass on bash 5.2 (Debian) and 5.1 (Rocky).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Harden update.sh against the class of failure that left a box silently stuck
on the old version, and make it testable without a real deploy.
Robustness (cascade):
- L5 loud failures: `set -Eeuo pipefail` (the -E/errtrace makes the ERR trap
fire inside functions too) + a report_failure ERR trap that names the phase,
exit code, line and command, plus always-on logging to
/var/log/serverkit/update-*.log. No more silent drop-to-prompt.
- L4 docker-path rollback: snapshot the previous git SHA, :rollback image tags
and dist.rollback before mutating; if the new backend is not healthy within
90s, revert to the snapshot and halt (was: warn and continue).
- L6 self-heal: pin COMPOSE_PROJECT_NAME (kills the symlink-rename warning) and
reclaim a stale inactive blue/green slot left by a prior failed hybrid run.
Testability:
- Parameterize the system dirs (SERVERKIT_NGINX_DIR / _LETSENCRYPT_DIR /
_SYSTEMD_DIR / _CONFIG_DIR) and add SERVERKIT_NO_LOG, so refresh_config can
run against fixtures instead of the host /etc.
- Make update.sh source-able via a BASH_SOURCE guard so functions can be
exercised directly.
- scripts/test/test_update.sh: plain-bash unit tests (no deps, no server) that
reproduce the missing-serverkit.conf regression and cover the
detection/slot/report logic.
- .github/workflows/scripts-ci.yml: bash -n + shellcheck + the unit tests on
changes to scripts/**, install.sh, serverkit.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduce a GitHub Actions workflow (release-smoke.yml) that builds the release tarball on pushes/PRs to dev/main for relevant paths, catching release-script issues early. Adjust scripts/build-release.sh rsync excludes to explicitly target backups directories (root/backups and backend instance/dev-data backups) instead of a broader exclude, preventing accidental omission of needed files during release packaging.
The release workflow was publishing Docker assets and source but never
the serverkit-vX.Y.Z-linux-{amd64,arm64}.tar.gz files that install.sh,
update.sh, and 'serverkit update' expect to download. This caused release
updates to fail with 'Failed to download the release tarball.'
- Make scripts/build-release.sh honor BUILD_ARCH for CI matrix builds.
- Add a build-release job that builds tarballs on native amd64 and arm64
runners and uploads them as artifacts.
- Wire the release job to download those artifacts, include them in the
GitHub Release, and checksum them.
- Add the one-line installer to the release notes body.
Mirror the Mapanare release pattern for the ServerKit panel:
- Trigger release on push to main (PR merge), v* tags, and workflow_dispatch
- Add workflow_call to backend-ci.yml so release can use it as a CI gate
- Read VERSION file, create/push v{VERSION} tag when releasing from main
- Build and push multi-arch Docker image jhd3197/serverkit:{VERSION} + latest
- Create GitHub Release with Docker install instructions
The Go agent has moved to its own repository:
https://github.com/jhd3197/serverkit-agent
Changes:
- Delete agent/ directory and all source, build, and packaging files
- Delete .github/workflows/agent-ci.yml and agent-release.yml
- Delete scripts/test/agent-test.ps1 (agent now builds in separate repo)
- Remove committed dist/serverkit-agent-windows-amd64.exe build artifact
- Update docs/INSTALLATION.md and docs/README.md links to point to the new repo
- Add migration notes to docs/AGENT_AUDIT.md, docs/REMOTE_ACCESS_ROADMAP.md,
SECURITY_AUDIT.md, and docs/plans/AGENT_FLEET_PHASES_3-4.md
Panel agent API endpoints under /api/v1/servers/agent/ and /api/v1/agent/
are retained — they are the control-plane contract with the standalone agent.
Verified:
- backend: pytest (371 passed, 12 skipped)
- frontend: npm run lint (0 errors)
Use the correct WiX extension version specifier (wix extension add --global WixToolset.Util.wixext/5.0.2). Updated the GitHub workflow, MSI Product.wxs comments, and PowerShell build script message to use the slash-style version token so the extension installs correctly with wix v5.
Refactor agent GitHub Actions and build tooling to separate concerns: add a dedicated build-ui job (upload/download agent-ui-dist) and a version job to resolve the release version; make downstream jobs depend on these outputs. Update workflow steps to consume artifacts/outputs (use needs.version where appropriate), and mark multi-platform jobs to not rebuild the UI. Add Makefile UI targets (build-ui, UI_DIST dependency, cleanup) so go:embed succeeds locally. Improve Windows MSI docs and build script: require specific wix tool/version and verify WixToolset.Util extension before building.
Switch MSI packaging to WiX Toolset v5: update CI to install the WiX Util extension, update Product.wxs comments and namespaces for v5 and show using the Util extension at build time, and enhance build.ps1 to pass the extension to wix build, fail loudly on non‑zero exit code, verify the MSI output exists and print the resolved output path. These changes ensure builds work with WiX v5 and provide clearer errors/output.
The Backend CI installed only requirements.txt (which doesn't carry the
test-only pytest dependency) and then ran `python -m pytest`, failing with
"No module named pytest". Add `pip install pytest` to the install step.
pytest is the only test-only import across tests/ (everything else they
import — cryptography, flask_jwt_extended, prompture, yaml — is already a
runtime dependency). Full suite: 232 passed, 12 skipped locally.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The agent embeds its desktop console via //go:embed all:dist
(internal/agentui/embed.go), which needs agent/internal/agentui/dist to
exist at compile time. The CI and release workflows ran go build/vet/test
without first building the React app (agent/ui -> vite build outputs to
that dist), so a fresh checkout failed with
"pattern all:dist: no matching files found".
Add a Node setup + `npm ci && npm run build` (in agent/ui) before the go
steps in both jobs of agent-ci.yml and in the release build job. Verified
the build command produces internal/agentui/dist locally.
Not a Go-version issue: wireguard-go@2026, gvisor@2025 and the agent all
declare go 1.23.1, and gvisor's gohacks build constraints are go1.20+
(no upper bound), so CI's Go 1.23 compiles them fine.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nothing ran the agent's tests or the backend suite automatically, so breakage
was only found by hand. Add two workflows:
- agent-ci.yml: go vet + go test on linux, plus a cross-compile build matrix
(linux amd64/arm64, windows amd64) to catch platform-specific breakage at
PR time. darwin is excluded — fyne.io/systray needs the macOS Cocoa toolchain
and can't cross-compile from Linux (it's built on a mac at release time).
- backend-ci.yml: install requirements and run the full pytest suite, including
the new end-to-end agent command-loop test.
Verified locally: go vet clean, all three cross-builds succeed, agent unit
tests and the full backend suite (136 passed) are green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follow-up to the injection fix (0f2299f), which I'd over-trimmed. Restores
original behavior with the safety fix kept:
- Re-add the if: guard so the job skips [skip ci]/[skip version] and its own
'chore: bump version' commits, so the bot's bump commit can't re-trigger
the workflow.
- Re-add the Create summary step (reads the message via env TRIGGER_MSG and
takes only the first line, so a multi-line/special-char body can't corrupt
the markdown table or the script).
- Bump detection matches a [major]/[minor] tag OR the original conventional
prefixes (BREAKING/major:, feat/feature/minor:), so existing feat:/BREAKING:
commits keep bumping minor/major as before.
- Keep the original dev-only trigger and paths-ignore.
The message reaches both steps via env (COMMIT_MSG / TRIGGER_MSG), never
spliced into run-script source. Verified: YAML parses and bump detection
returns the right type for feat:/BREAKING:/[minor]/[major]/plain messages,
including ones containing backticks, pipes and $(...).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The bump-version job did `COMMIT_MSG="${{ github.event.head_commit.message }}"`
inside a run: block. GitHub Actions text-substitutes ${{ }} into the script
source BEFORE bash runs, so a commit body containing backticks, $(...) or |
is spliced in raw — breaking the step (and an arbitrary-command-injection
vector). Commit e3337f0's body contained `vagrant up | Out-Host`, so the
backticks opened a command substitution and the pipe was a syntax error:
"syntax error near unexpected token `|`" — the reported CI failure.
Pass the message via env: COMMIT_MSG instead, so it reaches the step as an
inert environment variable that bash never re-parses. Verified by simulation:
the old form reproduces the exact error; the new form handles backticks,
pipes and $(...) safely and still detects [major]/[minor] markers.
Also removes three stray ``` markdown code fences (lines 64/70/71) that had
been pasted into the YAML, and the dead BACKEND_DIR var + placeholder
comment. YAML validated with a parser.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduce a native Windows desktop pairing experience and add ARM64 Windows builds/MSI.
Key changes:
- Add native Windows UI support: app.manifest, walk/win deps, icons, header image, and foreground activation helpers.
- Replace the old local HTTP/webview wizard with a native setup UI (remove wizard.html, refactor setupui). Add setupui.Run integration.
- Implement desktop/tray behavior: runDesktop/runTray refactor, single-instance mutex, detached spawn for the pairing wizard, desktop file-backed logging, and MessageBox wrapper for early errors.
- Build/CI updates: add windows/arm64 to build matrix, include -H=windowsgui for windows builds, produce per-arch MSI artifacts, and update release workflow summaries.
- Packaging & resources: add .syso resources for amd64/arm64, MSI build script updates, icon generation script and packaging tweaks, and update .gitignore to ignore dist and MSI outputs.
- Dependency and version bumps: update agent/go.mod/go.sum for walk/win and other indirect deps; bump VERSION to 1.5.4.
These changes enable a native pairing wizard on Windows (no browser/WebView2 required), keep the tray visible while the wizard runs, and add ARM64 support end-to-end (binary and MSI installers).
- agent/Dockerfile: bump golang base from 1.21 to 1.23 to match go.mod
- agent-release.yml: pin WiX to 5.0.2 to avoid the OSMF EULA prompt
introduced in WiX 7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The previous commit accidentally bumped the toolchain to Go 1.25 via
`go get`. Downgrade golang.org/x/term and golang.org/x/sys to versions
that work on Go 1.23 and update the agent-release workflow to match.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Introduce a full workflow/automation subsystem: new WorkflowEngine with DAG validation/execution (Kahn's algorithm), logic-if branching, variable interpolation, script sandboxing (timeouts, output limits), retry semantics, notification nodes, and an in-process WorkflowEventBus for event-triggered workflows. Backend API updates include webhook trigger and validate endpoints, auto-generation of webhook IDs on create/update, and services emitting events (git push, health check failures, app stopped, monitoring alerts). Add Alembic migration to create workflow-related tables and bump VERSION to 1.4.0. Also update .gitignore, add GitHub issue/PR templates, quick-start script, and various frontend workflow panel/component adjustments to support the new automation features.
Bump distro images (ubuntu:22.04 -> ubuntu:24.04, fedora:40 -> fedora:41) in the system utils test workflow. Make package installation commands less quiet and more robust: clear /var/lib/apt/lists/* before apt-get update and remove -q flags from apt-get/dnf/yum installs so logs are more informative and apt updates won't fail on stale lists.
Set DEBIAN_FRONTEND=noninteractive to prevent interactive prompts during image package installs, add shell: bash for the Install step, and normalize command -v checks/redirection so package manager detection and installs behave more reliably. Also remove excessive suppression of apt-get update/install output to surface failures; the pip3 pytest install fallback remains unchanged.
Remove the inline "Verify expected package manager" step from the GitHub Actions workflow and add a pytest in backend/tests/test_utils_system_integration.py. The new test (test_matches_expected_manager_from_ci) reads EXPECTED_MANAGER from the environment, skips when not set, and asserts PackageManager.detect() matches the expected value. This consolidates the CI verification into the test suite and simplifies the workflow.
Introduce a new GitHub Actions workflow (.github/workflows/test-system-utils.yml) that runs unit tests, distro-based integration tests in container images (ubuntu, debian, fedora, rocky) to validate package manager and systemctl detection, and an audit job that greps migrated service files for raw subprocess patterns. Add backend/tests/test_utils_system_integration.py: Linux-only integration smoke tests that directly import backend/app/utils/system.py (avoiding Flask deps) to verify PackageManager detection, command availability, and basic ServiceControl behavior. Designed for CI verification of system utilities across real distros.
Introduces a cross-platform system tray application for the agent, accessible via the new 'tray' command. Implements a local IPC HTTP server for tray/agent communication, exposes agent status, metrics, logs, and restart functionality. Updates build scripts, configuration, and documentation to support the tray app and IPC integration.
Change Docker Hub repository from serverkit/agent to jhd3197/serverkit-agent
to match the actual Docker Hub account.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduces Dockerfile, .dockerignore, and docker-compose.yml for containerized deployment of the agent. Adds packaging scripts for .deb, .rpm, and .msi installers, and updates the GitHub Actions workflow to build and release these formats. The Makefile and README are updated with Docker and package build instructions. The integration plan is updated to reflect completion of installation and distribution features.
Introduced Linux (install.sh) and Windows (install.ps1) installation scripts for ServerKit agent, and exposed new backend endpoints to serve these scripts and installation instructions. Added a GitHub Actions workflow (agent-release.yml) for automated agent builds and releases. Updated ROADMAP.md and SERVERS_INTEGRATION_PLAN.md to reflect progress on installation and distribution features.
Redesigned the README with improved layout, badges, architecture overview, and updated quick start instructions. Added a comprehensive docs/ARCHITECTURE.md file detailing system design, request flow, template system, port allocation, database linking, file paths, and troubleshooting.
- Add VERSION file (starting at 1.0.0)
- Add GitHub Actions workflow to auto-bump version on push
- patch: default for all commits
- minor: commits starting with "feat:" or "feature:"
- major: commits starting with "BREAKING:" or "major:"
- Add CLI commands: version, check-update
- Update 'serverkit update' to show semantic versions
- Compare local vs remote version before updating
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>