Comments, docstrings and a few strings cited plan numbers ("plan 29
#9", "plan 86 §B2") from a git-ignored folder, so they pointed at
nothing; one reached users in a bottleneck hint. Code and frontend
strings are unchanged apart from those citations (checked by AST and
token comparison). A vhost still carrying the old asset comment reads
as undrifted, and a guard test keeps new citations out.
The Prometheus, Grafana and Loki templates installed but connected
to nothing. A Grafana install now takes Metrics and Logs
attachments: the panel creates the data source through Grafana's
API with the recorded admin login, and a metrics attach also imports
a dashboard of the panel's fleet metrics. An attached app joins the
shared network, so Grafana reaches the source by name.
The nine extracted extensions are now published, signed, and merged
into the serverkit-extensions main catalog; the bundled offline copy
picks up the five new security-suite entries and the source/sha256/
signature fields on localkit, email, cloudflare-ops, and git.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
serverkit-extensions#3 published the signed first-party catalog and
restored serverkit-redis (re-pinned to the rebuilt v1.0.1 asset). The
bundled mirror already carried the signatures; this picks up the
serverkit-redis entry so test_matches_published_index agrees with main
again. Generated by scripts/sync-registry-index.sh.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Harness: bootstrap find/awk in distro-compatibility.py (AL2023,
Tumbleweed, SLES BCI minimal images lack them; the source-level
suites legitimately use both)
- Python gate 3.11-3.14: Arch/Manjaro rolling ship only python 3.14
with no versioned fallback packages (same trap as Debian 13/#99);
align scripts/update.sh, which had drifted to a 3.11-3.12 gate
- Gentoo: add emerge as a supported installer package-manager path
(install.sh, scripts/lib/pkg.sh, distro.py family, deps manifest);
provision via slotted dev-lang/python:3.13 -> 3.12
- Tests: move out-of-range stubs above the new ceiling, shadow all
locate_python candidate names (real python3.14/3.13 in Manjaro/
Gentoo images were winning over fixtures), cover the 7th manager
- Catalog: Gentoo is no longer a documented expected failure
Verified: test_lib 32/32, test_install 124/124, test_update 76/76,
pytest test_serverkit_installer 46/46, and all 6 previously failing
images now pass both quick and provision container probes (12/12).
The curated serverkit-recipes index is consumed like the themes registry
(cached remote index, bundled fallback, SERVERKIT_RECIPES_REGISTRY_URL
override). GET /recipes/registry[/<slug>] browses it; POST /recipes/runs
now accepts a registry_slug plus server_id — targeting a server finds or
creates the per-workspace Recipes project — and validated non-secret
params that pre-supply handoff inputs so only true secrets pause the run.
Frontend: Recipes catalog page (cards, category chips, install drawer
with running-server picker, preflight table, up-front inputs and an
asked-during-the-run secrets preview) under new Services and Marketplace
tabs; runs land in the deployment console.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`app/data/registry_index.json` is the Marketplace's offline fallback and a
mirror of serverkit-extensions/index.json on main. The registry gained
`serverkit-localkit` (v0.2.0, bundled) and the mirror was never updated, so
an offline panel would have offered a different extension set than an online
one -- and test_registry_bundled_index::test_matches_published_index failed
on every run.
Copied the entry verbatim into its published position. The rest of the file
already matched published field-for-field; this is the whole delta.
`builtin-extensions/serverkit-localkit/` ships in the panel at the same
version, so `bundled: true` is correct and the entry carries no source/sha256.
Nothing automates this mirror, so it will drift again on the next registry
publish.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
app/data/registry_index.json is what the Marketplace falls back to when the
live registry is unreachable, and what the test suite reads. Seven of its ten
entries carried a sha256 that does not match the artifact their own source URL
resolves to, at the same version: serverkit-gpu's zip hashes 3872d71f..., the
bundled copy claimed c861dafa.... A panel that fell back to this file would
download the correct, untampered release and reject it as tampered, on exactly
the panels already cut off from the network. It also sat nine entries and one
version behind (WordPress 1.0.0 against a published 1.0.1).
Nothing caught it because nothing checked it: the file was hand-maintained,
had no generator, and no test referenced it. A wrong-but-well-formed digest is
indistinguishable from a right one without fetching the artifact or the
published index.
Regenerated as a straight mirror of serverkit-extensions/index.json, and the
note now says it is a mirror and must not be hand-edited. The new test compares
the pinned (version, source, sha256) tuples against the published index and
skips only when the index is unreachable, so offline is not a failure but a
reachable mismatch is. Verified it fails against the old file, naming all seven
digests and the WordPress version, and passes against the regenerated one.
Also corrects the signed-releases roadmap line I marked done earlier today: the
verification path and the consent UX shipped, but no published release actually
carries a signature and the registry schema did not even document the field, so
every first-party install still takes the unsigned-consent path.
Flip DEFAULT_REGISTRY_URL to https://serverkit.ai/ext/index.json (the
long-planned go-live default: cached proxy of the raw index with logo URL
rewriting). Add logo fields to the bundled offline index so Marketplace
cards get real art even before the first successful fetch, and update the
registry tests + docs for the new default.
Analytics, CrowdSec, DNS Server, GPU Monitor, Kubernetes, Mail Server and
Automations (tramo) now live in their own repositories and install from the
registry as versioned, sha256-pinned zips. Their sources leave
builtin-extensions/, their pre-bundled frontends leave frontend/src/plugins/,
and registry_index.json gains a `bundled: false` entry for each so the
Marketplace offers them as normal registry installs.
The panel keeps only the wiring: comments at the former mount points explain
where each surface now comes from, and the gpu auto-install gate in
extension_migration.py is dropped since a host-probe can no longer decide to
re-vendor an extension that is not in this tree.
Also untracks backend/app/plugins/serverkit-{gpu,k8s,tramo}/, which were the
panel's own install artifacts rather than source. Committing those shipped a
second copy of code that now lives in three other repos, guaranteed to drift.
.gitignore now excludes the install path for every extracted slug on both the
backend and frontend side, so a local install can never be committed back.
Four tests from test_tramo_extension.py exercise panel core rather than the
extension (the retired /api/v1/workflows blueprint, the plan-45 event emitters
ported to EventService, and the docker_service double-emit fix); they move to
test_tramo_panel_core.py and stay here. The rest of the extension suites go
with their repos.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Featured order: Faro (100), Automations (90), WordPress (80),
Cloudflare Zone Ops (70), GPU Monitor (60). Scores set in each bundled
extension's manifest (both copies); Faro's lives in the registry index.
- Add illustrated covers for Kubernetes and WordPress (extension-icons +
resolver rules) so they stop falling back to generic category glyphs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- registry_service: keep featured/feature_score through normalization so
registry (bundled:false) extensions like Faro actually float to the top
and show the Featured ribbon (they were being stripped).
- ExtensionIcons: give the Postfix/Dovecot "Email Server" the envelope and
the Stalwart "Mail Server" the server-rack icon so they stop looking like
duplicates ('email' matched before the bare 'mail' rule).
- Drop Faro's logo override so it uses its full-bleed illustrated cover
(92px) instead of the 44px brand-logo slot.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Match the published serverkit-faro v1.0.2 release (lean zip) in the
offline registry fallback.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add Faro illustrated cover (extension-icons/faro.png) + resolver rule so
serverkit-faro shows a 3D lighthouse instead of a flat glyph.
- Mark Cloudflare Zone Ops featured (score 95) in both plugin.json copies.
- Add a wordpress.detail.panel PluginSlot so the Faro (and future WP)
extensions can render on WordPress site pages.
- Sync the registry offline fallback with the Faro v1.0.1 entry (featured).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stop stripping the v2 fields in registry_service normalization: add repo,
logo, bundled to _FIELDS. Repo-relative logos (assets/<slug>/<file>) are
resolved to absolute URLs against the index URL they came from, so one
relative path works for both the raw-GitHub index and the serverkit.ai
/ext endpoint. Bundled entries are excluded from the Browse catalog by
default (they duplicate builtin cards) and reachable via
?include_bundled=true. Detail modal gains a Source repo link.
Tests: v2 normalization, relative-logo resolution, v1 unaffected, bundled
exclusion + include_bundled endpoint flag. Full test_registry.py green (19).
Docs: EXTENSIONS_REGISTRY.md documents schema_version 2 + v2 fields.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>