Piped execution leaves BASH_SOURCE unset, so the sourceability guard's bare
${BASH_SOURCE[0]} was an unbound variable under `set -u` and aborted the
install before main() ever ran:
bash: line 2107: BASH_SOURCE[0]: unbound variable
This broke the one-liner README/DEPLOYMENT document, on every distro — not
just the Debian 13 it was reported on (reproduced on debian:13 bash 5.2.37,
ubuntu:22.04 bash 5.1.16, almalinux:9 bash 5.1.8). CI never saw it because
every job runs `bash install.sh` from a checkout, where BASH_SOURCE IS set.
Use the same non-empty-first guard scripts/install.sh already carries, and
add the proving test the panel installer was missing (T41) — the agent
installer has had its twin since the same fix landed there.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The full WordPress suite now lives at github.com/jhd3197/serverkit-wordpress
as a standalone runtime-ESM extension (backend blueprints/services, game
dashboard UI, tests, CI). Installed from the registry or offered during
onboarding from the bundled snapshot. WP data models stay core per D1
(documented core-data-seam).
Runtime-ESM extensions (starting with serverkit-wordpress) need slot
mounting and error containment from the host; additive, versioned in
lockstep frontend/backend.
Create/update validation fails loudly naming the missing extension
instead of orphaning monitors; health sweep no-ops with zero WP sites
(plan 52 phase 3 task 17). StatusComponent.wordpress_site_id stays core
per D1.
The wordpress template kind + wordpress-external-db preflight move behind
a template-provider hook the extension supplies; the backend filters the
catalog so the WP card simply does not appear when WP is absent — no
frontend change needed (plan 52 phase 3 task 16).
Extensions register event types at load; wordpress.* types now come from
the WP extension instead of a hardcoded core catalog (plan 52 phase 3
task 15). emit_wp stays core as a dumb emitter helper.
VALID_TARGET_TYPES is now provider-driven; the wordpress_site branch
moves behind a provider the WP extension registers. ProtectionPanel /
RestoreDrawer read available types from the API; policies whose provider
is absent surface a clear missing-provider state instead of crashing
(plan 52 phase 3 task 13).
Extensions can register providers into core engines at load (backup
targets, event types, template kinds) via a core_hooks module; idempotent,
process-lifetime like blueprint registration. WP extension supplies its
entries through builtin-extensions/serverkit-wordpress/backend/core_hooks.py
(plan 52 phase 3, D4).
App.jsx /wordpress* title fallbacks removed (manifest page_titles cover
the routes); sidebar preset hiddenItems no longer hardcode the wordpress
slug — nav sources from extension contributions.
5 WordPress* pages + components/wordpress (40 files) + 3 _wordpress*.scss
partials move from core into builtin-extensions/serverkit-wordpress/
frontend/ (synced to frontend/src/plugins via the baked-glob pattern).
200 imports rewritten to serverkit-sdk; remaining @/ imports only for
genuinely host-internal modules. main.scss drops the WP partials — the
extension bundle imports its own styles. npm build + lint green.
TabGroupLayout, Modal, ConfirmDialog, Spinner/LoadingState, EmptyState,
Skeleton(SkeletonBoundary), and the ui/* form kit (Button, Input, Select,
Switch, ...) as generic re-exports so an extension page can mirror core
page chrome without deep imports. Proven out by the WordPress frontend
relocation (plan 52 phase 4).
Unknown categories already derived/filtered gracefully; this adds
games to the canonical order and gives it a lucide Gamepad2 icon
ahead of serverkit-minecraft landing in the registry.
The four minecraft test files now live in serverkit-minecraft/tests/
(panel-hosted via SERVERKIT_MINECRAFT_DIR loader). Ratchet floor
3280 -> 3197 (-83 minecraft tests; collected 3222, floor intact).
The Minecraft game-server extension now lives at
github.com/jhd3197/serverkit-minecraft as a standalone runtime-ESM
extension (analytics/gpu repo pattern). It is installed from the
registry like any first-party extension, no longer bundled in-tree.
scripts/sign-extension.mjs signs a bundle with an ed25519 author key;
EXTENSIONS.md documents the format, key model, and verdict behaviors.
Generated private keys live in gitignored scripts/keys/.
Consent card shows permissions, version gate, and signature state
(Signed/Unsigned/Unknown signer/Invalid) with honest copy; 'Install
anyway' destructive path for acknowledged risk; invalid = disabled.
Proactive hardening from an internal audit of the same broken-authorization
class as GHSA-6w78-q5vm-rfmh (authentication checked, app/workspace-level
authorization skipped):
- deployment_jobs: job detail/logs/retry resolve the job and gate on
can_access_app / can_operate_app (app-less jobs: requester or admin);
global job listing is admin-only
- secrets_webhooks: every vault/secret/webhook-endpoint/delivery by-id
route resolves to its workspace and 404-seals non-members; secret
reveal and signing-secret regeneration require workspace owner/admin;
dead local admin_required placeholder removed
- shared_resources: variable-group CRUD and attach/detach gate on the
resolved scope (workspace role / can_edit_app / can_operate_app),
closing deploy-time env injection into foreign apps
- queue_bus: message receive/complete/fail/list on system-owned groups
are admin-only; user-owned groups restricted to their owner
- docker: raw container inspect (exposes env vars) and container logs
are admin-only, matching Decision 7; per-app logs stay app-gated
- databases: raw SQL query endpoints, host-level metadata reads, and
process lists are admin-only; per-app managed database flows unchanged
Adds 4 persona-matrix regression suites (74 tests) and bumps the
test-count ratchet.
GHSA-6w78-q5vm-rfmh: four git deployment/webhook read endpoints checked
authentication but skipped app-level authorization, letting any active
user (even a foreign viewer) read cross-tenant deployment history and
logs that can contain secrets from pre/post-deploy scripts.
- git.deployments/<id>: resolve deployment -> app, 404/403 via
app_access_tier before returning any log bytes
- git.deployments/webhook/<id>: gate on _webhook_visible_to (app-linked
webhooks follow app visibility; unlinked stay panel-wide, plan 29 #11)
- deploy.history & deploy.webhook-logs: app_id queries require
app_access_tier; global (no app_id) queries are panel-admin only
Adds backend/tests/test_git_deployment_authz.py (9 persona-matrix
regression tests) and bumps the test-count ratchet.
Co-authored-by: Tyler Boykin <25166954+CaptBoykin@users.noreply.github.com>
Adds a new YouTube “Watch the Demo” badge/link near the top badges in the main README and the Spanish, Portuguese, and Simplified Chinese README translations so users can quickly find the product walkthrough.
Copilot review on the GHSA-rm3m-9mvw-68fh patch caught two issues:
- _BACKEND_DIR/_INSTALL_DIR were one level too shallow (backend/app and
backend/ instead of backend/ and the install root), which left
<install>/.env and frontend/dist reachable on the deployed layout —
the exact PoC path from the advisory. _BACKEND_DIR stays in
PROTECTED_ROOTS so flat layouts (code at /app) are covered too.
- The ALLOWED_ROOTS check used a bare startswith, so e.g. /optfoo
matched the /opt root. Both checks now require an exact match or a
path-boundary prefix.
New tests pin the level math (the existing cases computed the expected
layout independently and passed on Windows for the wrong reason) and
simulate the deployed layout with the install dir inside an allowed root.
New builtin job security-feed (daily) pulls the normalized advisory feed
from serverkit.ai/api/security-feed.json (a cached proxy of the repo's
published GitHub Security Advisories) and:
- notifies admins (security.alert, critical) when the running panel
version falls inside an advisory's affected range, once per advisory;
- fires a one-time post-fix reminder after an upgrade crosses a fix
boundary when the advisory declares a "## Post-upgrade actions" section
(e.g. rotate JWT_SECRET_KEY after GHSA-rm3m-9mvw-68fh).
Dedupe keys, the last-good feed copy, and the previously-seen version live
in SystemSettings, so restarts never re-notify and outbound failures serve
the cached feed. Opt out via the security_feed.enabled setting. Privacy
page on serverkit.ai updated to disclose the daily call.