Skip to content

feat: finish 002 backend — Steam display names, structured player entries, rcon.authentication - #635

Merged
ValgulNecron merged 14 commits into
masterfrom
claude/project-thread-ypqnlg-002
Oct 9, 2026
Merged

ValgulNecron merged 14 commits into
masterfrom
claude/project-thread-ypqnlg-002

Conversation

@ValgulNecron

Copy link
Copy Markdown
Collaborator

Before: the Steam display-name resolver (api/internal/steam/) existed but nothing used it, and it negative-cached every id whenever a call to Steam failed. Nuclear Option player lists were a regex over the JSON body, so faction was lost. Templates had no way to say "this console has no password", so the operator minted an RCON Secret nobody read. Spec 002 had 87 unchecked tasks, many already built.

After: with an optional Steam Web API key (api.steam.apiKeySecretRef), GET /servers/{name}/players adds displayName to structured entries, and falls back to raw Steam IDs on any failure. The agent returns entries: [{steamId, faction}] for JSON player lists while players stays the flat Steam-ID list, so the current dashboard keeps working. GameTemplates can set spec.rcon.authentication: false (default true) to skip the password Secret. Spec 002 now has 26 open tasks: module repo work, the UDP join tests the maintainer kept open, the Players tab design pass, and real-server checks.

How:

  • fix(api): call-level failures (unreachable, 5xx, 429, timeout, netguard block, bad JSON) no longer write negative cache entries (data-model §8d-i); the warning is rate-limited.
  • feat(api,chart): GAMEPLANE_STEAM_API_KEY (env only) plus four cache knobs; the hydration handler has a 1.5 s budget and otherwise passes the agent's bytes through unchanged. Kick/ban/unban stay keyed on Steam ID.
  • feat(agent): JSON {"Players":[...]} list output is decoded into entries; other games keep the regex path.
  • feat(operator): RCONSpec.Authentication *bool (default true) with a CEL rule rejecting false together with a password source; make generate && make manifests output is included (the other CRDs only change their bundle-hash stamp). web/src/types.ts mirrors the field (type only).
  • Tests: Nuclear Option remote-command cases, resolver/singleflight/hydration cases, address-in-use and pool-exhausted e2e (new one-address kind pool pool-e2e-single, used only by that test).
  • Docs: install, security threat model, changelog, module authoring.
  • Spec: tasks ticked with evidence, plan Decisions 10/11 and the T022 decision recorded, US5 scenarios amended (T118).

Not in this PR: the Players tab (T095/T096/T102) waits for the Pencil design pass. The Nuclear Option template changes (authentication: false, repin to the org image, resources, constraints, actions, specs.md) go to GameplanePanel/module first, followed by a submodule bump. Until then, Nuclear Option servers get an unused password Secret again, which is harmless.

Local checks: go build ./... and compile-only go test -c for every touched package; tests run in CI.

🤖 Generated with Claude Code


Generated by Claude Code

claude added 11 commits October 9, 2026 02:27
A failed GetPlayerSummaries call (unreachable, 5xx, 429, timeout,
netguard block, bad JSON) no longer writes negative cache entries; only
ids a successful response omitted are negative-cached (002 data-model
§8d-i). The outage warning is rate-limited to once a minute. Adds the
T097/T100 resolver and singleflight cases.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
GAMEPLANE_STEAM_API_KEY (env only, from api.steam.apiKeySecretRef) turns
on the Steam name resolver; four flag+env knobs tune its in-memory
cache. GET /servers/{name}/players adds displayName to structured
entries within a 1.5s budget and otherwise passes the agent response
through byte for byte. Moderation routes stay keyed on Steam ID.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
When the list command returns {"Players":[{"steamId","faction"}]}
(Nuclear Option get-player-list), the snapshot carries entries with
steamId and faction, and players stays the flat list of Steam IDs so
existing clients are unaffected. Other games keep the regex path.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
Nuclear Option's remote-command port has no authentication and is
loopback-only, so the per-server password Secret was never read.
Exempt it like cli (002 T024).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
GameTemplate spec.rcon.authentication (default true) keeps today's
behaviour. false means the console has no authentication, so the
operator mints no <gs>-rcon Secret, mounts nothing for the agent and
injects no password env; a CEL rule rejects false together with
passwordSecretRef, passwordEnv or passwordFile. Replaces the
protocol-specific nuclearoption exemption with this field.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
pool-e2e-single (one address, autoAssign false) exists only so
TestAddressPool_PoolExhausted can exhaust a pool without starving the
parallel address-pool tests. The second server must report
AddressAssignment False with reason AllocationFailed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
Ticks the 61 tasks that are implemented (36 already on master before
this branch, 25 by this branch) with evidence, records the 2026-10-09
maintainer rulings in plan.md Decisions 10 and 11, and writes the T022
display-name decision into spec.md. Join-test, module, design and
real-server tasks stay open.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
@ValgulNecron ValgulNecron added type: feature New capability or user-facing addition area: operator controller-runtime operator and CRDs area: api REST/WebSocket gateway area: agent in-pod sidecar area: chart Helm chart and deployment area: e2e kind-based end-to-end suite area: specs spec-kit feature specs and design docs labels Oct 9, 2026 — with Claude
@ValgulNecron ValgulNecron self-assigned this Oct 9, 2026
@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 51 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: GameplanePanel/Gameplane/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c08a4f54-5640-4db6-963d-dc3f3951e792

📥 Commits

Reviewing files that changed from the base of the PR and between 953f497 and 3643a6f.


📒 Files selected for processing (47)
  • CHANGELOG.md
  • agent/internal/players/players.go
  • agent/internal/players/players_test.go
  • agent/internal/rcon/nuclearoption_test.go
  • api/cmd/main.go
  • api/internal/steam/resolver.go
  • api/internal/steam/resolver_test.go
  • api/internal/steam/singleflight_test.go
  • api/internal/ws/dialer.go
  • api/internal/ws/players_hydrate.go
  • api/internal/ws/players_hydrate_test.go
  • charts/gameplane/crd-manifests/gameplane.local_backups.yaml
  • charts/gameplane/crd-manifests/gameplane.local_backupschedules.yaml
  • charts/gameplane/crd-manifests/gameplane.local_clusters.yaml
  • charts/gameplane/crd-manifests/gameplane.local_gameservers.yaml
  • charts/gameplane/crd-manifests/gameplane.local_gametemplates.yaml
  • charts/gameplane/crd-manifests/gameplane.local_modules.yaml
  • charts/gameplane/crd-manifests/gameplane.local_modulesources.yaml
  • charts/gameplane/crd-manifests/gameplane.local_networkcaptures.yaml
  • charts/gameplane/crd-manifests/gameplane.local_restores.yaml
  • charts/gameplane/crds/gameplane.local_backups.yaml
  • charts/gameplane/crds/gameplane.local_backupschedules.yaml
  • charts/gameplane/crds/gameplane.local_clusters.yaml
  • charts/gameplane/crds/gameplane.local_gameservers.yaml
  • charts/gameplane/crds/gameplane.local_gametemplates.yaml
  • charts/gameplane/crds/gameplane.local_modules.yaml
  • charts/gameplane/crds/gameplane.local_modulesources.yaml
  • charts/gameplane/crds/gameplane.local_networkcaptures.yaml
  • charts/gameplane/crds/gameplane.local_restores.yaml
  • charts/gameplane/templates/api.yaml
  • charts/gameplane/values.yaml
  • deploy/kind/e2e.sh
  • docs/install.md
  • docs/module-authoring.md
  • docs/security.md
  • modules
  • operator/api/v1alpha1/gametemplate_types.go
  • operator/api/v1alpha1/zz_generated.deepcopy.go
  • operator/config/crd/gameplane.local_gametemplates.yaml
  • operator/internal/controller/gameserver_rcon.go
  • operator/internal/controller/gameserver_rcon_test.go
  • specs/002-nuclear-option-ip-pool/plan.md
  • specs/002-nuclear-option-ip-pool/spec.md
  • specs/002-nuclear-option-ip-pool/tasks.md
  • test/e2e/buckets.sh
  • test/e2e/pool_assignment_e2e_test.go
  • web/src/types.ts


  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

CI Report - 3643a6f

run 37977306202 - attempt 1

0 failed - 26 passed - 0 skipped - 67m47s elapsed

Coverage

Module Measured Gate Margin
web L95.45 S93.95 B88.62 F91.74 L92 S92 B82 F76 +1.95

Changed

Area Files +/-
agent/ 3 +772/-1
api/ 7 +710/-17
test/ 2 +288/-0
specs/ 3 +73/-67
charts/ 20 +98/-18
operator/ 5 +108/-1
docs/ 3 +80/-0
deploy/ 1 +26/-2
(root) 2 +23/-1
web/ 1 +3/-1

Slowest jobs

Job Duration
e2e telemetry / amd64 (kind) 23m7s
e2e telemetry / arm64 (kind) 21m56s
e2e capture overhead (kind) 12m38s
e2e multicluster / amd64 (kind x2) 9m40s
e2e multicluster / arm64 (kind x2) 9m14s

e2e buckets run

api-agent, api-auth, api-mods, api-rbac, api-roles, bot-fast, multicluster, operator, ratelimit, telemetry, upgrade

Copy link
Copy Markdown
Collaborator Author

e2e operator (amd64 and arm64) fails only in the new TestAddressPool_PoolExhausted (pool_assignment_e2e_test.go:974). The operator behaves as intended: the second server gets AddressAssignment=False/AllocationFailed. The failure comes from the test's extra check that the endpoint host is empty. By design, endpointsFromService falls back to the Service ClusterIP while no LB ingress exists (operator/internal/controller/gameserver_status.go:1253), so the host reads 10.96.x.x.

The proposed fix is to assert that the host is not the pool's only address and that the endpoint pool is empty. Because this changes a test assertion, it waits on the maintainer's sign-off. Every other e2e test in the bucket passed.


Generated by Claude Code

claude added 2 commits October 9, 2026 18:54
While allocation has failed the operator reports the Service ClusterIP
as endpoint host. Assert the exhausted pool address was not handed out
and no pool is stamped, instead of requiring an empty host.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
@ValgulNecron
ValgulNecron marked this pull request as ready for review October 9, 2026 20:11
@ValgulNecron
ValgulNecron merged commit 781d013 into master Oct 9, 2026
92 checks passed
@ValgulNecron
ValgulNecron deleted the claude/project-thread-ypqnlg-002 branch October 9, 2026 20:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: agent in-pod sidecar area: api REST/WebSocket gateway area: chart Helm chart and deployment area: e2e kind-based end-to-end suite area: operator controller-runtime operator and CRDs area: specs spec-kit feature specs and design docs type: feature New capability or user-facing addition

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants