Repository navigation
·
161 commits
to master
since this release
Immutable
release. Only release title and notes can be modified.
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. - Telemetry receiver dashboard and public summary: a private,
token-protected dashboard (DASHBOARD_LISTEN_ADDR, default:8081) with
7-, 30-, 90- and 365-day views, durable daily aggregates
(RETENTION_DAYS, default730, minimum365), per-install activity
records that expire (ACTIVITY_EXPIRY_DAYS, default90, minimum31),
a per-source daily ingest limit (INGEST_SOURCE_DAILY_LIMIT, default
20),TRUSTED_PROXY_CIDRS, anID_PEPPERsecret and an optional public
GET /v1/summary(PUBLIC_SUMMARY=true). Helm values:
api.telemetry.enabled,api.telemetry.interval,
api.telemetry.receiver.{persistence,dashboard,publicSummary,pepperSecretRef,retentionDays,activityExpiryDays,ingestSourceDailyLimit,trustedProxyCIDRs}. - Proof-of-work on telemetry ingestion (off by default): a receiver with
INGEST_POW=trueservesGET /v1/challengeand requires a solved
challenge on/ingest(428 pow_required/pow_invalid,503 pow_busy
when its used-challenge set is full). The difficulty is zero up to
INGEST_POW_TARGET_PER_MINchallenges a minute (default60), then rises
with the rate betweenINGEST_POW_MIN_BITS(default0) and
INGEST_POW_MAX_BITS(default22, at most26), and decays one bit
every five minutes. New metrics:gameplane_telemetry_pow_challenges_total
andgameplane_telemetry_pow_bits;gameplane_telemetry_refused_total
gains the reasonspow_required,pow_invalidandpow_busy, and
gameplane_telemetry_rate_limited_totalthe routechallenge. Helm values:
api.telemetry.receiver.ingestPow.{enabled,targetPerMinute,minBits,maxBits}.
The API reporter solves a challenge when its destination offers one and
sends without it otherwise. See
docs/telemetry-provider.md. - Provider runbook:
docs/telemetry-provider.md
covers deploying the receiver, TLS, keeping:8081private, secrets and
rotation, retention, scraping/metricsand backing uptelemetry.db. - Optional Steam display names on player lists: with
api.steam.apiKeySecretRef.nameset to a Secret holding a Steam Web API key
(key nameapi-keyby default), the API looks up public display names for
Steam IDs in player lists throughISteamUser/GetPlayerSummaries/v2, with an
in-memory cache tuned byapi.steam.cache.{maxEntries,ttl,negativeTTL,timeout}
(defaults 10000 entries, 12h, 15m, 2s). Without a key, or when Steam is
unreachable, player lists show raw Steam IDs as before. The key is env-only,
never logged and never sent to the browser. See
docs/install.mdand
docs/security.md. - Nuclear Option player lists are structured: the agent's player output
for JSON player lists now includes an entry per player (steamIdand
faction), which the API uses for display-name lookup. - Language selection and translations (spec 019): the dashboard can be
shown in another language. A user's language choice is saved to the account (or
to the browser when signed out), and an admin sets the instance default. Languages are
shared packs underi18n/locales/; a language is listed once its pack is at
least 80% translated, and anything missing falls back to English. French is
the first pack and is listed once it reaches 80%.
Dates, numbers and relative times follow the active language. A pseudo
language (en-XA) exists for maintainers behindVITE_I18N_PSEUDO=1and is
never listed in a release. Seedocs/translating.md. - Translated server messages (opt-in
problem+json): API errors are sent
asapplication/problem+jsonwith a stablemessageIdand arguments only
when the request lists that type inAccept; every other client keeps the
unchanged English plain-text body. The dashboard opts in and shows the
message in the active language. Game server condition messages carry
status.conditionArgsso the dashboard can translate them too; the English
messageis unchanged. - Notification language per destination: each notification destination
has an optionallanguage; notifications and test sends to Discord, email
and webhooks are rendered in it, and destinations with none use the
instance default. Webhook payloads gain additivelanguage,titleand
textfields; existing fields are unchanged. - Module translations: a module can ship
locales/<tag>.jsonnext to
module.yaml(OCI layer typeapplication/vnd.gameplane.module.locale.v1+json
and the same files in every other source). The operator validates them on
install, stores the valid entries in a<template>-localesConfigMap and
reports problems as theLocalesValidcondition; install never fails
because of translations. Each file is read up to 900 KiB and all of a
bundle's files together up to 4 MiB.gp-module i18n extract|stampand
gp-module validatesupport authoring. See
docs/module-authoring.md. - Fleet-wide node inventory: clusters are organized on their own pages and
a Nodes page lists the nodes of every cluster you can see, with the same
search and filters as Backups (PR #859). - Game performance and relay monitoring: bounded per-game performance and
relay metrics (PR #838). - Stopped multi-volume Restic recovery: a stopped server with several data
volumes can be recovered from its Restic backups (PR #861). - Wake on connect from server settings: users can turn wake on connect on
from the server's Lifecycle settings (PR #818). - Reserve less than the limits: a server can request less CPU and memory
than its limits (Burstable QoS) from Resources and Create Server (PR #815).
Changed
- No RCON Secret for unauthenticated consoles: a new optional
GameTemplatefieldspec.rcon.authentication(defaulttrue) lets a
template declare a console with no password, such as Nuclear Option's
loopback-only remote-command port. Whenfalse, the operator mints no
per-server<gameserver>-rconSecret, mounts nothing for the
agent and injects no password environment variable.
Removed
- Hell Let Loose module:
hell-let-looseis withdrawn from the
official catalog. Its dedicated-server files are distributed only to
Team17's licensed hosting partners, so no public image can install it.
Its hand-run e2e test and probe package are removed with it.
Security
- Pre-release hardening (PR #862): OIDC discovery, key fetches and code
exchange, and operator OCI registry dials go through the dial guard; agent
and capture proxies can no longer override the API's security headers; a
login-device cookie stops failed logins elsewhere from locking the owner
out; the API pod no longer mounts the agent CA key; a ValidatingAdmissionPolicy
(Kubernetes 1.30+) limits waker service accounts to the wake annotation;
template env Secret and ConfigMap references follow the server ownership
rule; the agent serves regular files only and confines mod installs to the
mods root; the dashboard ships Monaco in the image and sends a
Content-Security-Policy and security headers; share tokens stay out of
access and error logs. - Snapshot restores authorize their data source against the live Backup
owner and reject unfinished or aborted snapshots (PR #756). - Operator Secret access is scoped to the configured namespaces (PR #757).
- Image CVE fixes: eMudhra CA distrust and Alpine/Debian updates in game
images, the Tailscale tunnel built with fixed Go modules, and updatedexpat,
musl,zlib,brotliandcurlin the dashboard image (PRs #775, #845,
#816). - Standalone credential protection: encryption keys are kept outside
database volumes, with durable publication, fail-closed file-access checks,
read-only provisioned custody, and authenticated transactional rotation.
Database and key backups need separate access policies; recovery requires
the matching key. See storage and recovery. - Remote workload boundaries: standalone connections require verified TLS,
reject unsafe destinations at dial time, and bound finite responses, watch
frames, and retained observations. Private networks remain reachable unless
destination CIDRs restrict them; configureGAMEPLANE_REMOTE_ALLOWED_CIDRS
orapi.remoteAllowedCIDRsfor the workload APIs and gateways. Module and
template authorization follows the selected cluster in every deployment mode.
See security.