Repository navigation
Releases
v0.4.0
A pre-v1 release with every change made since v0.3.0: an independent central
panel, languages, the extended telemetry tier, safer backups and restores,
fleet-wide node inventory, and a pre-release security hardening pass. Read the
upgrade notes below before upgrading; several of them change behaviour. It
does not claim v1 or production support; see docs/roadmap.md.
Fixed
- Backup, restore and wipe exclusion (#718): backups, restores and wipes
of the same server now take one lifecycle ownership, so a backup can no
longer read a filesystem a restore or wipe is changing, and wipe workers are
drained before workloads come back (PRs #760, #619). - Backup captures: backup workers are prepared before quiesce, CSI
snapshot captures are bounded, and a capture taken across a game container
restart is invalidated instead of being kept (PRs #836, #846). - Backups with retention disabled are kept (PR #618).
- Wake on connect: wake requests are bounded, HostPort hand-offs are
preserved, and shared wakes retry within their budget instead of failing on
the first cold-start error (PRs #840, #860). - Tunnels: frp identities are isolated per server and report relay
connection health; Tailscale forwards every advertised TCP and UDP port and
keeps active UDP sessions (PRs #768, #765). - New files are created atomically and never overwrite an existing file
(PR #621). - Standalone Helm CRD isolation: the central panel profile excludes bundled
native CRDs and their apply hook/RBAC without requiring--skip-crds.
Default operator installations keep Helm's native CRD lifecycle; existing
CRDs and their custom resources are retained when a profile omits them.
Upgrade Notes
- Breaking: admin-level grants need a full administrator: holders of
users:manage,roles:manageorconfig:managewithout*can no longer
grant*or another admin-level permission, edit or reset an administrator,
or edit auth providers (/admin/config/auth,/admin/authneed*)
(PR #862). - Breaking: kubelet probes reach only probe ports: a new per-server
<server>-probesNetworkPolicy admits kubelet CIDRs to the game container's
probe ports only, on by default withnetworkPolicies.probeIngress.enabled.
The old all-portsallow-kubelet-probesrule renders only when that is
falseor extraprobePortsare listed. Set
networkPolicies.probeIngress.enabled: falseto restore the old rule
(PR #862). - Breaking: custom CSS: stylesheets with
\escapes or absolute,
http(s):or protocol-relative//references are now rejected (PR #862). - Share links get their own Ingress:
/shareand/sharesgo through a
second Ingress,gameplane-share, with access logging off for ingress-nginx
(ingress.shareLinks.*). Other controllers need their own switch in
ingress.shareLinks.annotations; seedocs/install.md
(PR #862). - Password reset ends every session of that account (migration
019_session_epoch.sql, applied on API startup) (PR #862). - The API is a singleton in every mode: every database driver uses the
Recreatestrategy andapi.replicasother than 1 is rejected, so upgrades
no longer overlap two API processes (#726, PR #758). - Auxiliary resource requests and management placement: agent,
config-init, sentinel, tunnel and Restic pods now request resources on every
install, and chart-managed pods accept placement settings. Game and
auxiliary pods can restart on upgrade; see
docs/release-notes.md(#724, PR #762). - Standalone panel/API: run the central panel with Docker Compose or the
standalone Helm profile, without a local game cluster or operator. Compose
needs no Kubernetes installation on the panel host.
Register remote clusters explicitly. Back up the database and matching
credential encryption key separately, with restricted access and encrypted
storage for key backups. Supplied profiles use key storage outside the database
volume. Preserve the original key when migrating legacy/data/panel.key
installations. See standalone installation. - Breaking: selected-cluster module/template grants: in combined and
standalone installations, catalog permissions now require a cluster-wide
grant on the selected cluster or wildcard cluster. A grant onlocalretains
local access but no longer authorizes a remote catalog. Before upgrading,
identify users who rely on remote catalog access and grant a role containing
modules:read,modules:manage,templates:read, and/ortemplates:write
on each intended remote cluster, selecting All namespaces. Grant only the
operations each user needs; namespace-only grants do not authorize catalogs.
See grant workload access. - Telemetry is on by default for new installs, after a first-login
notice: a new install with a telemetry destination in effect now shares
basic and extended data by default; the stock destination is the project's
receiver at telemetry.gameplane.net. The first admin to sign in sees a
notice that lists every field of both tiers and names the destination;
nothing is sent before then. Basic isversion,serversand
templates. Extended adds a random install ID, the Kubernetes minor
version, a distribution category, node architectures and a node-count
band, server counts per official module plus onecustomcount, feature
flags (wake-on-connect, tunnel types, packet capture, backups, single
sign-on, audit forwarding), a cluster-count band, the database kind, the
UI language, the install's public signing key and the send time. Each
tier has its own toggle in Admin Settings → Telemetry, which also
shows the destination, a preview of the next report and an install-ID
reset. The data-handling statement is at
https://gameplane.net/telemetry/. See
docs/install.md. - Installs whose basic toggle was already on start sending to the
project's default receiver: an install that saved Send anonymous usage
metrics while no destination was configured (so it had no effect) starts
sending basic reports to the project's default receiver
(telemetry.gameplane.net) after upgrade.
Extended stays off until an admin turns it on, and installs that never
saved a choice stay off. Installs already using a custom
api.telemetry.endpointor the bundled receiver keep sending only there.
Setapi.telemetry.enabled=falsebefore upgrading to prevent any
sending. - Empty
api.telemetry.endpointnow means the project default:
It now means the project's default receiver
(https://telemetry.gameplane.net/ingest), so the admin toggles have an
effect on a stock install. Setapi.telemetry.enabled=falsefor a hard off (air-gapped
clusters, privacy-sensitive installs); it overrides the endpoint, the
bundled receiver and the admin toggles, and hides the notice. - The receiver's
/metricsmoved to the dashboard port and needs the
dashboard token: the receiver's Prometheus endpoint is no longer on
:8080; it is on:8081and accepts only
Authorization: Bearer <DASHBOARD_TOKEN>. Without
api.telemetry.receiver.dashboard.tokenSecretRef.namethere is no
dashboard listener and no metrics endpoint, and the chart renders no
ServiceMonitorfor the receiver. Update your Prometheus scrape config
or set the token Secret. See
docs/telemetry-provider.md. - The bundled receiver now stores data: with
api.telemetry.receiver.persistence.enabled(defaulttrue, 1Gi) it
keeps daily aggregates for 24 months and activity records for 90 days in
SQLite on a PVC, and runs a single replica with aRecreatestrategy.
helm upgrade --reuse-valuesfrom 0.3.0 needs no new values; with no
persistenceblock the receiver keeps using anemptyDir, as before. - The receiver's
DASHBOARD_TOKENmust be at least 32 characters: a
receiver withDASHBOARD_TOKENset to a shorter value now exits at
startup (DASHBOARD_TOKEN must be at least 32 characters). Replace the
Secret behindapi.telemetry.receiver.dashboard.tokenSecretRefwith a
value generated from 32 random bytes, for example
openssl rand -base64 32, before upgrading. Replacing the token
invalidates browser sessions and loses no data. Receivers with no token
(no dashboard) are unaffected. See
docs/telemetry-provider.md.
Added
- Independent central panel: Docker Compose runs the API/dashboard without
host Kubernetes; a standalone Helm profile runs them without a central game
operator or workloads. SQL stores registrations, settings, and encrypted
credentials; explicitly selected remote clusters host games through their own
operators and agents. - Credential maintenance: standalone keys have separate generated storage
or read-only provisioned custody, the offline transactionalrotate-panel-key
command, andPUT /clusters/{name}/kubeconfigpreserving registration identity
and grants.PUT/DELETE /clusters/{name}/gatewaymanage remote gateway
credentials;api.remoteAllowedCIDRsrestricts workload API and gateway
destinations. See standalone setup. - Extended telemetry tier: a second, separately consented tier with a
random install ID, environment, game-usage and feature-adoption
categories. Every value comes from a fixed set, a band or a number; no
names, namespaces, hostnames, addresses, player counts or custom module
names. Reports are signed (Ed25519, key derived from a per-install secret
and the install ID); a receiver binds each ID to its first key and refuses
forged, stale and replayed reports. See
[docs/security.md](docs/security.md#telemet...
v0.3.0
The first Gameplane release without a pre-release suffix, a pre-v1 release. It
contains every change made since v0.2.0-beta.8, including the changes first
previewed in v0.3.0-rc.1 and the pre-release audit fixes summarized under
0.3.0-rc.2 below. It does not claim v1 or production support; see
docs/roadmap.md.
Upgrade Notes
-
Network capture feature adds an emptyDir volume to every game pod: The
network capture feature (protocol reverse-engineering and admin-only traffic
diagnostics) requires a pre-provisioned volume on every game pod, whether or
not that server will ever opt into capture. This is a structural requirement:
Kubernetes ephemeral containers can add containers to a running pod without pod
recreation, but cannot add volumes. The captureemptyDirvolume must exist in
the pod template before the ephemeral sidecar is injected, so it is provisioned
unconditionally at cluster install time.
Consequence: every existing GameServer will roll once on upgrade to this
release. Each pod will be recreated with the new template (containing the
empty capture volume), interrupting any active player sessions. This is a
one-time event at upgrade time and does not repeat on each server start. Plan
your upgrade window for a time when you can tolerate a rolling restart of all
game servers. The upgrade note for FR-001 and SC-007 (specification items
tracking pod immutability) is updated to reflect this: non-opted-in game servers
are no longer byte-identical between captures disabled and enabled; they carry
an empty, unused capture volume. What they do NOT carry is the capture sidecar
container itself (no ephemeral container, noCAP_NET_RAW, no network access
change). -
Owner-only server operations need the owner or an admin: transferring
ownership, editing collaborators, wiping data and deleting a server now need
the server's owner or an admin. Operator-role users keep their other server
permissions, but can no longer run these four operations on servers they
don't own. Servers without a recorded owner (for example ones created with
kubectl or GitOps) can be transferred, wiped or deleted only by an admin. -
Playit tunnel NetworkPolicy egress widened: the operator-managed
NetworkPolicy for a GameServer using theplayittunnel provider now adds
an unrestricted egress rule (all ports and protocols, any destination)
alongside the DNS/advertised-ports rule every provider gets. Previously
playit got only that rule, so it could not reach its relay (F-262). -
Helm 3 reinstalling over leftover CRDs runs the CRD-apply hook: a
helm installonto Gameplane CRDs left behind by an uninstalled release
runs thecrds.autoApplyhook to bring them up to date, so air-gapped
clusters needcrds.autoApply.imagemirrored for that case. Under Helm 4,
existing CRDs are applied natively; CRDs last applied by v0.2.0-beta.8 or
earlier need a one-timehelm install --force-conflicts(F-218).
Added
- Configurable backup/restore Job limits: the restic backup and restore Jobs' retry limit and deadline are now Helm values (
operator.backupJobBackoffLimit, default2;operator.backupJobActiveDeadlineSeconds, default86400), passed to the operator as--backup-job-backoff-limit/--backup-job-active-deadline-seconds. - Multicluster gateways and unified server management: an optional
private mTLS agent gateway (with its own Helm deployment) lets one dashboard
and API manage authorized game servers across independent clusters.
Dashboard, Servers, Backups and Search combine every site with optional
location filters, and console, files, players, mods and captures are routed
to the selected server's cluster (#542). - User theme customization (feature 016): Settings → Theme & Appearance
offers preset themes (Modern Pink, Legacy Orange) and custom color selection
with live WCAG AA contrast validation. Custom accent and surface colors are
persisted per user; appearance mode (light/dark) can follow the surface color.
Custom CSS overlay allows per-user style tweaks; all customizations support
import/export. Safe mode (?safe-mode=1or keyboard shortcut) suspends custom
CSS and shows a banner without reloading. Theme bootstrap on login prevents
flash; preferences are read/write controlled via RBAC (every user sees only
their own) (#415). - Network capture sidecar (feature 003): Admin-only, on-demand packet capture
from running GameServer pods. Enabled per server via a Dashboard toggle, capture
runs as an ephemeral sidecar container (no pod restart), is recorded as PCAPNG
(Wireshark-compatible), and auto-expires after 7 days or a configurable size/duration
limit. Download streams directly from the capture sidecar via the existing
<gs>-agentService. The captureemptyDirvolume is pre-provisioned on every
pod at cluster install time (the upgrade consequence above). Every capture
session is recorded in the audit log with admin-only playback to the
captures:managerole. For protocol reverse-engineering and diagnostics (#256). - Easy module building & authoring toolkit (feature 010): Scaffolds, validates,
previews, and packages custom game modules. Thegp-moduleCLI supports three
starter archetypes (steamcmd,java,generic) with configurable ports,
storage, and metadata; offline validation with source-line diagnostics; dry-run
manifest rendering (simulatesautoFromMemoryLimit); and OCI bundle packaging
with media-type and size-limit enforcement. The web dashboard (Modules page)
offers a BuildModuleDialog with live validation, YAML editor, bundle download,
and cluster installation. API endpoints:/modules/builder/{scaffold,validate,preview,export}(#370). - 13 new top-steam-game modules (feature 015): FiveM, Farming Simulator 25,
Euro Truck Simulator 2, Mount & Blade Bannerlord, tModLoader, Team Fortress 2,
BeamMP, Left 4 Dead 2, The Isle, ARK: Survival Evolved, Arma Reforger, Hell
Let Loose, and Squad. Gameplane publishes four Gameplane-owned container
images:ghcr.io/valgulnecron/gameplane/fivem(FiveM + txAdmin),farming-simulator-25
(Wine/Xvfb runner),euro-truck-simulator-2(Wine runner), andbeammp
(BeamMP + non-crashing diagnostic idle). All modules are signed with Cosign
keyless signatures (#369). - Nuclear Option dedicated server support: New
nuclearoptionremote-command
protocol implemented in the agent's RCON client set, wired into console /
players / quiesce; a Gameplane-owned, SteamCMD-basednuclear-option
container image (no official image exists upstream); genericmin/max/
minLength/maxLengthconstraints onConfigField, enforced in
materializeConfigfor every module, landed alongside it (#252, #255, #260). - Install-time configuration (feature 006): Two Helm values for zero post-deploy
configuration:- Helm-seeded OIDC role mappings:
api.oidc.groupsClaim,api.oidc.defaultRole,
andapi.oidc.roleMappings.{admin,operator,viewer}seed a read-only "helm"
OIDC provider, so OIDC-only installs need nobootstrap-adminrun. Dashboard
Settings → Authentication can override any role's group list (stored in
helmOverride.roleMappings); changes take effect on next login (no restart).
Reset viaDELETE /admin/config/auth/role-mappings/{role}. - Default StorageClass for game-data PVCs:
operator.gameDataStorage.storageClassName
(Helm value) sets a cluster-wide default with precedence: GameServer >
GameTemplate > install-time > cluster default. Missing StorageClass surfaces
asPVCProvisioningFailed(recoverable) (#282).
- Helm-seeded OIDC role mappings:
- Share link expiry options (feature 017): Removed the hard 90-day cap that
outlived long-running servers. Create requests now carryexpiresAt(RFC3339
instant) orneverExpires: true(not both, not neither = 400 error). Dashboard
offers presets (15/30/60/90 days, No expiry) and custom date picker; 30 days
is pre-selected. Past instant dates are rejected. The deprecatedexpiresIn
field still works for one release (#392, #396). - Console WebSocket robustness: Fixed 403 errors when dashboard is reached
on non-default ports (e.g.,kubectl port-forward svc/gameplane-web 8088:80)
by forwarding$http_hostinstead of$hostin the nginx config. Added guard
onsend()before socket open: input sent while CONNECTING is queued (max 500
items) and flushed on open; input after reconnect is dropped (no silent replay);
input after close is no-op. Queue tests verify behavior with fake sockets that
throw like real browsers (#416). - Existing PVC for SQLite: Helm
api.storage.existingClaimallows installs
to point the API database to a pre-existing PersistentVolumeClaim, enabling
storage migration and lifecycle separation from the main Helm release (#390). - REST and CLI console protocols: Agent implementation for
rest(generic HTTP
for games with HTTP admin APIs like FiveM txAdmin) andcli(local process
execution for PTY-only games like Terraria). Both are wired to console, players,
quiesce, lifecycle, and quick-action endpoints. Thercon.protocolenum is
nowsource;telnet;websocket;battleye;satisfactory;palworld;nuclearoption;rest;cli;none(#369). - Security audit remediation: Multiple fixes from a comprehensive security
audit: share links are isolated by cluster; GameServer setting/image/service
account/environment/tunnel changes are permission-checked; Secret and ConfigMap
references must belong to the target server; optional network policies restrict
audit and telemetry services to API traffic; SteamCMD image pinned to a stable
version (#350). - Mod archive path confinement: Symlink-escape and zip-slip guards hardened
across every extraction and non-extract upload call site in the agent's mods
handler (ConfinePath/ `Con...
v0.2.0-beta.8
A dependency sweep: all Go modules bumped to latest available versions,
web dependencies updated, and CI image pins aligned to current stable releases.
Added
- Wake-on-connect for idle auto-sleep: a sentinel component (distroless Docker
image, configured viaoperator.sentinelImage) holds advertised ports while a GameServer
is asleep and wakes it on a genuine connection attempt. Opt-in per server via
spec.idle.wakeOnConnect(default false). New CRD fields:
GameServer.spec.idle.wakeOnConnect(bool) andGamePort.wakeProtocol
(enum:minecraft|terraria|generic|none, defaultgeneric). New shared
modulegameproto/for Minecraft and Terraria handshake parsing; UDP-only
games use a generic packets-in-window heuristic. Works across all four expose
modes; Hostport has asymmetric limitations documented indocs/roadmap.md.
Costs one small pod per sleeping server. - Load-balancer address pools: GameServers can now request a specific address
pool or explicit public IP when exposed as LoadBalancer services, via optional
spec.networking.addressPoolandspec.networking.addressCRD fields. The
operator translates these to the cluster's load-balancer flavor (configured
viaoperator.addressManagerHelm value:metallb|cilium|none,
defaultnone): MetalLB gets pool →metallb.io/address-poolannotation and
address →metallb.io/loadBalancerIPs; Cilium gets pool →
gameplane.local/lb-poollabel (admin mirrors it in
CiliumLoadBalancerIPPool.spec.serviceSelector) and address →
lbipam.cilium.io/ips. A newAddressAssignmentstatus condition tracks the
assignment outcome with eight reason codes (Assigned, AssignmentPending,
PoolNotFound, AllocationFailed, AddressInUse, ServiceNotReady,
IgnoredForExposureMode, NoAddressManagerConfigured). Dashboard support added
for setting and viewing pool/address. Seedocs/networking.md.
Security
- Signing key rotated: cosign key type changed from Ed25519 to ECDSA P-256
(cross-signed for trust continuity; seedocs/key-rotation.md). - Transparency logging enabled: all published images, the Helm chart (now
signed for the first time), and official module bundles are signed and
recorded in the public Sigstore Rekor transparency log. Signing is now
fail-closed in CI (missingCOSIGN_PRIVATE_KEYfails the release).
Changed
- Go dependencies: telemetry-receiver, sentinel, and mcp-server updated
to latest go-openapi versions (github.com/go-openapi/{jsonpointer,jsonreference,swag}
v0.2x → v1.x); operator updated with 50+ indirect dependency bumps (go-git
v5.19.1 → v5.19.2); api'smodernc.org/sqlitev1.54.0 → v1.55.0; agent and
e2e test suite indirect dependencies (k8s.io, golang.org/x packages) brought
current. - Web dependencies:
@tanstack/react-virtualv3.14.8 → v3.14.9,
lucide-reactv1.26.0 → v1.27.0,@types/nodev26.1.1 → v26.1.2,
globalsv17.7.0 → v17.8.0,jsdomv29.1.1 → v30.0.1,postcssv8.5.23 →
v8.5.25. - CI image pins:
setup-envtestrelease-0.19 → release-0.24, Kubernetes
(envtest) 1.31.0 → 1.36.2 (now in sync with the Makefile), andkindv0.24.0 →
v0.32.0. - Container image defaults: restic/restic 0.18.1 → 0.19.1 (charts/gameplane/values.yaml operator.resticImage default) and nginxinc/nginx-unprivileged 1.30-alpine → 1.31-alpine (web/Dockerfile base image).
modules/build.shgained--tlog-uploadflag (passed by the release
pipeline for official bundles); default stays offline for air-gapped authoring.- Module bundles are now signed by the pushed manifest digest.
build.sh
previously took the firstsha256:token inoras pushoutput, which is not
necessarily the manifest — a layer digest printed in full would have been
signed instead (operator verification unchanged).
Notes
- TypeScript held at 6.x:
@typescript-eslint/parser@8.65.0declares
peerDependencies: typescript >=4.8.4 <6.1.0, so upgrading to TS 7.x would
break type-aware linting. Reevaluate when@typescript-eslint/parserpublishes
a v8.x major that supports TS 7+. - ESLint held at 9.x:
eslint-plugin-react@7.37.5declares no^10peer
range, so upgrading to ESLint 10.x would break React linting. Reevaluate when
eslint-plugin-reactpublishes a v8+ major or a 7.x patch that widens the
peer range. - Prometheus client_golang:
telemetry-receiver's
github.com/prometheus/client_golangv1.24.1 is at latest; no update
available.
v0.2.0-beta.7
A stabilization release: a full audit of code, the live dashboard, the API, and
the docs ahead of wider external testing. Highlights below.
Security
- api: the WebSocket console/logs/files/players/actions/status/mods routes
and the mod-id / mod-update handlers now reject a?cluster=selector that
isn't the local cluster (404). These handlers only ever act on the control
plane's own cluster, but RBAC authorized the namespaced permission against the
caller-supplied?cluster=— so a user bound only to a registered remote
cluster could pass?cluster=<remote>to satisfy RBAC and reach same-named
local servers (RCON/PTY console, mod writes, log/file reads).
Single-cluster installs were unaffected. - operator:
Expose: Hostportnow binds only advertised template ports to
the node — non-advertised admin ports (RCON/query/telnet consoles) are no
longer exposed on the node IP, matching the Service and NetworkPolicy filters.
Fixed
- api: the long-lived SSE
/eventsstream and the WebSocket routes are no
longer force-closed after 60 s by the global request-timeout middleware (which
also spammedsuperfluous response.WriteHeaderinto the API log every
minute). The 60 s deadline still applies to every normal request/response
route. - api:
/modules/catalognever emits"sources": nullfor an
installed-but-uncatalogued module (it serializes[]), which previously
crashed the entire Modules page at render. - web: a
Failedmodule can now be uninstalled — its Uninstall button was
disabled, trapping the user with a broken install and no way to remove it. - agent: the Source-RCON and telnet console clients gained the auth-failure
cooldown the other protocol clients already had — a wrong RCON password is no
longer re-sent on every poller tick (which could self-inflict a Source-engine
sv_rcon_maxfailuresban). Both now wrap the sharedErrAuthsentinel, and
ban/kick reasons reject all control characters, not just CR/LF. - operator:
BackupSchedule.status.lastSuccessfulTimeis now populated from
the newest successful backup (the dashboard "Last run" andkubectl"Last"
columns were always blank); theModulePending path clears a stalePulling
condition;GameServersetPhasestampsobservedGeneration; and the
ModuleSource "indexed N of M" status message no longer goes negative for
git/http/local/upload sources. - chart: the operator (and API) metrics
ServiceMonitors now select a
Service that actually exists and carries the matching
app.kubernetes.io/namelabel — operator metrics, the PrometheusRule alerts,
and the Grafana dashboard were never scraped before. - web: per-node pod counts show
—instead of a fake0/<cap>when the
count is unavailable (matching CPU/memory), plus assorted accessibility labels
and a fix to the cluster page's developer-facing empty-state copy.
Changed
- chart: the
defaultModuleSourcetemplate fallback is nowoci(matching
the shippedvalues.yamldefault) rather thangit.
Docs
- Refreshed stale references: the current version, the 8th (
Cluster) CRD, the
RBAC database tables, the OCI default module source, thetelemetry-receiver
andmcp-servercomponents, the fullModuleSourcetype list, the
architecture diagram's reconcilers, and the changelog link footer. Clarified
that SQLite is the production-tested database driver and Postgres is
experimental (build-tag-gated, work-in-progress).
v0.2.0-beta.5
Added
- ci/supply-chain: the cosign public key is now published — committed
at the repo root ascosign.pub, exported by CI (job summary +
artifact on every edge publish), and shipped as a release asset. Both publish
workflows now verify each signature right after signing with the key
derived from the CI secret, and fail the publish if the committed
cosign.pubdrifts from the signing key. README and docs gained
cosign verifyinstructions (the key is Ed25519; offline/keyed, so
verification takes--insecure-ignore-tlog=true). - ci: tagged releases now get a GitHub Release page automatically —
notes extracted from the tag's CHANGELOG section, prereleases flagged,
cosign.pubattached, idempotent on re-runs. (beta.4's page was backfilled
by hand.) - website: Gameplane has a public marketing + docs site at
https://valgulnecron.github.io/gameplane-website/ — features, game
showcase, an AMP comparison, and the full documentation set, designed
screen-first indesign.pen(18 frames) and built with Astro. The source
lives in the separate
gameplane-website
repo, mounted here as thewebsite/submodule. - web: the last UI-audit parity items — a show/hide toggle on the login
password field, user emails shown under display names on the Users page,
port overrides editable in the Create Server wizard's Network step (the CRD
and Settings tab already supported them), and "Back up now" relocated to a
header button + dialog on the Backups page, matching the design.
Changed
- ci: the three kind e2e jobs (core / extended / game bot) were collapsed
into a single job running the same three suites, in the same order, against
one cluster — they were already fully serialized by the shared concurrency
group, so the split only cost duplicate image builds, cluster setups, and
queue slots (~15-20 min per run). Docs-only changes no longer trigger the
test pipeline at all (paths-ignore); no test was removed.
v0.2.0-beta.4
Added
- operator: fleet metric
gameplane_gameservers{phase=…}exported on the
operator's/metricsendpoint — one gauge per GameServer lifecycle phase,
computed from the controller cache at scrape time (so it never drifts from
reconcile state). The bundled Grafana dashboard gains "GameServers
running/failed" stats and a stacked "GameServers by phase" graph, and
prometheusRules.enabledgains aGameplaneGameServerFailedalert. Until
now the dashboard and alerts plotted only controller-runtime internals; this
is the first domain metric. - operator: companion fleet metric
gameplane_backups{phase=…}(one gauge
per Backup phase), with a "Backups failed" stat + stacked "Backups by phase"
graph on the dashboard and aGameplaneBackupFailedalert — a silently failed
backup is a data-loss risk, so it's worth paging on. - ci: the published component images (
:edgeon everymainpush and the
versioned images on av*release) are now keyed-cosign-signed by digest
(offline, no Rekor), matching the official module bundles. Verify with
cosign verify --key cosign.pub ghcr.io/valgulnecron/gameplane/<component>.
Gated onCOSIGN_PRIVATE_KEY, so publishing still works before the key is set.
Signing and publishing run only onmain/tags, never on PRs. - api: server-side audit-log export —
GET /admin/audit/export?format=csv|json
(admin-only) streams the entire audit trail, optionally bounded by RFC3339
since/until. Unlike the dashboard's client-side CSV (only the loaded page),
this returns the full log in one download for compliance/archival, streamed
row-by-row so a large table isn't buffered in memory. - api: outbound audit-log webhook push sink — set
api.audit.webhook.url
and the API POSTs each audit event as JSON to that endpoint (a log aggregator's
push API, a SIEM, or your own receiver), alongside the database. It mirrors,
never gates: events always persist, and a slow or unreachable endpoint never
blocks or fails a request (bounded async buffer, drop-and-count on overflow,
surfaced atgameplane_audit_webhook_events_total{result=sent|failed|dropped}
on/metrics). An optionalAuthorizationheader is Secret-sourced
(api.audit.webhook.authSecretRef), never a flag. - audit-syslog-bridge: a new, generic HTTP-JSON → syslog relay image that
sits behind the audit webhook sink, so audit events can be forwarded to a
syslog/SIEM collector (RFC 5424 over TCP, TCP+TLS, or UDP). Deploy the bundled
relay withapi.audit.webhook.syslogBridge.enabled=true+
…syslogBridge.syslog.addr, and the chart auto-points the webhook at it (off
by default). The bridge forwards the request body verbatim, so it works for
any JSON webhook source, not just Gameplane.
Changed
- chart: the bundled
defaultModuleSourcenow defaults to a git source
that indexes the publicgameplane-modulerepository, so the official games
appear in the Modules page out of the box — no OCI registry to publish first.
SetdefaultModuleSource.type: ocito pull (optionally cosign-signed) bundles
from a registry instead. Breaking values change: the former top-level
url/insecure/modules/pullSecretName/verifykeys moved under
defaultModuleSource.oci.*. - chart: the official module-signing public key (ed25519) now ships in
defaultModuleSource.oci.verify.cosignPublicKey, so verifying official bundles
is justtype: oci+oci.verify.enabled: true— no key to paste. Still off
by default.
Fixed
- operator: the Servers list "Node" column was always blank — nothing ever
set thegameplane.local/nodeannotation the dashboard reads. The GameServer
reconciler now keeps it in sync with the node the game pod is scheduled on
(and clears it when the server is stopped), so the column shows real placement.
v0.2.0-beta.3
First release published to the GitHub Container Registry — installable with a single Helm command (no helm repo add).
Install
helm upgrade --install gameplane oci://ghcr.io/valgulnecron/charts/gameplane \
--version 0.2.0-beta.3 \
--namespace gameplane-system --create-namespace \
--set ingress.host=gameplane.your-domain.testTrack the rolling beta instead with --set image.tag=edge. See docs/install.md.
Published artifacts (GHCR)
- Chart:
oci://ghcr.io/valgulnecron/charts/gameplane:0.2.0-beta.3 - Images (linux/amd64 + arm64):
ghcr.io/valgulnecron/gameplane/{operator,api,agent}:0.2.0-beta.3
Highlights
- Full GHCR publishing —
release.yamlpublishes version-pinned multi-arch images + the OCI Helm chart on everyv*tag;publish-edge.yamlpublishes rolling:edge+:sha-<short>images on everymainpush. - One-command Helm install — chart
image.tagdefaults toappVersion, so a released chart pulls matching images with no overrides. - BREAKING: CRD API group renamed
gameplane.gg→gameplane.local— manifests are nowapiVersion: gameplane.local/v1alpha1. Recreate CRDs after upgrading; nov*release ever shipped the.gggroup. - Operator image now reports its real build version; bundled observability (
prometheusRules,grafanaDashboards); signed-module-bundle support (opt-in).
Note: GHCR packages are private on first publish — the maintainer must flip
gameplane/{operator,api,agent}+charts/gameplaneto public for anonymous installs.