Add SCUM Source RCON transport
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-07-23
|
||||
@@ -0,0 +1,77 @@
|
||||
## Context
|
||||
|
||||
The prior UE4SS DLL change provisions `ue4ss/Mods/scum_simple_rcon/config.ini` before a normal SCUM start, but the declared Run `rcon` adapter is only an envelope placeholder. The shipped DLL is a Source RCON server that is intentionally loopback-only and accepts raw SCUM commands on its game-thread queue; `SendChat <type> "message" [SteamID64]` is its supported chat form.
|
||||
|
||||
Platform and Run already use leased jobs, signed Run-only input routes, scoped workspaces, and durable job state. Sending a raw admin command through the generic remote-adapter `inputs` map would persist it in the Platform job and Run journal, conflicting with the requested no-history/no-audit behavior.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- Let an authorized server operator send a typed chat message or raw SCUM command through the existing job channel without a second confirmation or command audit record.
|
||||
- Transfer a command exactly once to the active leased Run worker without storing the raw text or RCON password in Platform persistence, job assignments, Run journals, browser DTOs, logs, or result messages.
|
||||
- Bind every dispatch to a ready, selected Windows amd64 UE4SS DLL declaration and a fixed Source RCON loopback plan.
|
||||
- Have Run authenticate to `127.0.0.1` using the protected generated config and implement the Source RCON wire protocol with bounded I/O.
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- Do not modify, build, or redeploy the UE4SS DLL source as part of command transport.
|
||||
- Do not create a generic remote TCP/RCON gateway, expose an RCON host or password, or allow browser-to-Run sockets.
|
||||
- Do not persist raw command text, chat text, source responses, a command history, or per-command audit events.
|
||||
- Do not retry a mutating command automatically, provide a Linux `.dll` fallback, or implement a separate Linux UE4SS `.so` runtime.
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision: Use a dedicated typed SCUM RCON request instead of generic remote-adapter inputs
|
||||
|
||||
Platform will expose a typed server-scoped request that accepts either a chat payload (`type`, message, optional SteamID64) or a bounded raw command. It validates the source DLL grammar and formats chat as `SendChat` internally. It validates ownership, the declared RCON capability, selected runtime binding, ready extension release, Windows amd64 endpoint, and the selected profile's RCON transport before it creates a job.
|
||||
|
||||
The job contains only an opaque input reference and a frozen `source-rcon` connection plan: extension key/mod key, logical config reference, and port. It contains no host, command, response, or secret. The existing generic remote-adapter endpoint remains suitable for declared non-secret inputs but is not used for raw SCUM commands.
|
||||
|
||||
Alternative considered: put `command` in `ExecutionInput.Inputs`. Rejected because Platform persistence, job claims, and Run's durable journal would retain the command.
|
||||
|
||||
### Decision: Use a one-time in-memory input broker fenced by the active Run lease
|
||||
|
||||
Platform stores each validated command in a mutex-protected, TTL-bounded in-memory broker before the corresponding job becomes claimable. The broker key is the job ID and cannot overwrite an outstanding submission with the same idempotency key. The signed Run-only RCON-input route first verifies endpoint, session, job, lease, attempt, capability, and frozen plan, then consumes and removes the payload.
|
||||
|
||||
The RCON job has exactly one attempt. A Platform restart, expired broker entry, worker crash after consume, or repeat input read fails closed rather than replaying a possibly mutating game command. Job/audit/result summaries use only generic delivery state.
|
||||
|
||||
Alternative considered: encrypting a durable broker row. Rejected because the explicit product boundary is no raw command persistence; encryption would still create history and recovery/replay semantics.
|
||||
|
||||
### Decision: Freeze a source-RCON loopback plan from the selected ready UE4SS extension
|
||||
|
||||
Platform derives the config reference from the extension's declared DLL layout (`ue4ss/Mods/<modKey>/config.ini`) and freezes the published port plus mod/extension identity. Because the actual SCUM executable may be below the workspace root, Run also owns a verified deployment-state marker that records the scoped logical config location written during DLL activation. The frozen plan carries only that safe marker reference; Run validates its extension/mod/port and expected config suffix before it reads the protected file. Run accepts only the `source-rcon` kind, Windows amd64, safe logical references, and an unprivileged declared port. There is no configurable host; Run always dials `127.0.0.1:<port>` in the server's scoped workspace.
|
||||
|
||||
The generator is corrected to write the DLL's actual `bind_address=127.0.0.1` setting. Run rejects a managed config whose port or bind address no longer matches the frozen plan.
|
||||
|
||||
Alternative considered: resolve paths or credentials in Platform. Rejected because Platform must not receive host paths or the generated RCON password.
|
||||
|
||||
### Decision: Treat Source RCON result bodies as sensitive transient data
|
||||
|
||||
Run authenticates, executes one command, and reads bounded response packets until the DLL's empty response sentinel. It classifies an `error:` response as a failed job but returns only a safe status/error code; it never includes raw command text, password, or response body in logs, artifacts, result messages, or Platform-facing payloads.
|
||||
|
||||
Alternative considered: stream full RCON output to the browser. Rejected because source responses may echo command text or game/player data and would reintroduce command history through job results/logs.
|
||||
|
||||
### Decision: Give the management console two direct entry points
|
||||
|
||||
The existing server detail surface gets a compact chat form and a raw-command form. Both submit immediately using typed API contracts and display only the current safe queue/result status. They intentionally do not add a confirmation modal, saved form history, command list, secret field, host field, or response transcript.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [Platform or worker restarts during a command] → the broker payload is gone or consumed; the job fails closed and an operator can explicitly submit a new command.
|
||||
- [SCUM/UE4SS is not loaded or the port is unavailable] → Run returns a safe connection/auth/protocol failure without falling back to a remote address.
|
||||
- [An RCON response echoes sensitive input] → Run only classifies it and does not surface the body.
|
||||
- [A user submits an unsupported chat target or malformed text] → Platform rejects it before a job/broker entry is created.
|
||||
- [A DLL declaration is still unpublished] → the feature stays unavailable until real immutable release pins are published and selected.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Deploy Platform, Run, plugin manifest, and management-console changes together.
|
||||
2. Publish a real ready DLL declaration, ensure the Windows UE4SS bootstrap is present, and restart SCUM so Run writes the managed loopback config.
|
||||
3. Verify `rcon.status` or a harmless `rcon.chat` through the console on a non-production server, then send a broadcast and an allowed admin command.
|
||||
4. Roll back by removing the new Run capability/using the previous Platform and Run releases; no persistent commands or secrets require migration or cleanup.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- The current SCUM manifest is intentionally unpublished; end-to-end production dispatch remains gated until the publisher supplies the real DLL URL, checksum, size, executable checksum, and UE4SS ABI.
|
||||
- Future command-output streaming would need a separate transient, authorization-reviewed design rather than reusing durable job results.
|
||||
@@ -0,0 +1,30 @@
|
||||
## Why
|
||||
|
||||
The SCUM UE4SS lifecycle now provisions a protected, loopback-only Source RCON listener, but Run's declared `rcon` adapter is still a placeholder that reports success without connecting to the listener. Operators therefore cannot actually send chat text or SCUM admin commands through the platform, and raw commands must not become a durable command-history or audit feature.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add a typed SCUM RCON dispatch path for direct chat delivery and raw SCUM admin commands, with no secondary confirmation step and no persisted command/audit payload.
|
||||
- Freeze a ready Windows UE4SS extension's safe loopback Source RCON connection metadata into a single-attempt Run job; reject unpublished, incompatible, or non-SCUM extension states before dispatch.
|
||||
- Keep the raw command only in a bounded, one-time, in-memory Platform input broker. The signed active Run lease retrieves it once; database jobs, Run journals, browser responses, audit events, logs, and result messages contain no command text or RCON password.
|
||||
- Replace Run's placeholder RCON adapter with a bounded Source RCON client that reads the generated protected config inside its scoped workspace, authenticates only to `127.0.0.1`, and sends the command using standard framed packets.
|
||||
- Add a server-management-console RCON panel for chat broadcasts/targeted chat and raw commands. It reports safe queued/succeeded/failed state without building a command history.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `scum-source-rcon-command-dispatch`: Platform authorization, one-time command delivery, safe browser contracts, and SCUM-specific dispatch constraints.
|
||||
- `run-source-rcon-execution`: Run-side loopback Source RCON authentication, packet exchange, response classification, and failure handling.
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- None.
|
||||
|
||||
## Impact
|
||||
|
||||
- `platform/`: domain/DTO/API contracts, command validation, transient input broker, fenced Run-only input endpoint, lifecycle/extension resolution, and focused tests.
|
||||
- `platform_web/`: typed API client, schemas, and the existing server-detail management surface.
|
||||
- `plugins/`: SCUM lifecycle capability declaration and manifest tests.
|
||||
- Independent `run/`: protocol copy, Platform client, Worker dispatch, Source RCON adapter, and unit/integration tests.
|
||||
- The UE4SS DLL source remains unchanged. No user-side compiler, generic remote socket, direct browser-to-RCON connection, Linux DLL substitute, raw command persistence, or command audit trail is introduced.
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Run executes a frozen Source RCON plan over loopback
|
||||
Run SHALL execute a `source-rcon` plan only for Windows amd64 and only by dialing `127.0.0.1` at the frozen declared port. It SHALL resolve the plan's generated config through the scoped workspace, read the protected password locally, and use Source RCON authentication and framed command/response packets. It SHALL not accept a browser-provided host, socket, path, or password.
|
||||
|
||||
#### Scenario: Valid loopback Source RCON command completes
|
||||
- **WHEN** Run receives a valid frozen plan and one-time command for a running compatible SCUM server
|
||||
- **THEN** it authenticates to the local DLL listener, sends the command, consumes the terminal response sentinel, and completes the job with a safe success status.
|
||||
|
||||
#### Scenario: Unsafe plan or local configuration is rejected
|
||||
- **WHEN** a plan is not `source-rcon`, is non-Windows, has an unsafe config key/port, or the local config is missing, non-loopback, or inconsistent with the frozen port
|
||||
- **THEN** Run fails before opening a socket or sending a command.
|
||||
|
||||
### Requirement: Run bounds and redacts Source RCON I/O
|
||||
Run SHALL bound command bytes, packet sizes, response bytes, response packet count, dialing, authentication, and command execution by the job context. It SHALL classify an RCON error response as a failed job but SHALL NOT persist or return the raw command, password, response body, config contents, or local path in logs, artifacts, progress, or result messages.
|
||||
|
||||
#### Scenario: Source RCON error response remains private
|
||||
- **WHEN** the DLL returns an `error:` response or malformed response framing
|
||||
- **THEN** Run returns a safe error code/message without exposing the returned body or submitted command.
|
||||
|
||||
### Requirement: Source RCON transport is at-most-once
|
||||
Run SHALL retrieve the command from the active Platform input route once per job and SHALL not retry a command after input, authentication, dial, or response failure. It SHALL not fall back to the placeholder remote adapter, a generic TCP address, `rundll32`, process injection, or a Linux loader.
|
||||
|
||||
#### Scenario: Lost one-time input does not replay a command
|
||||
- **WHEN** Run cannot retrieve a fresh one-time command or loses execution after it was consumed
|
||||
- **THEN** it fails the job safely and does not send a duplicate command.
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Platform dispatches a typed SCUM Source RCON command
|
||||
Platform SHALL accept a server-authorized typed request for either a SCUM chat message or a bounded raw SCUM command only when the installed plugin declares `remote.run.rcon.command`, the selected runtime profile declares the RCON transport, the endpoint reports the capability, and a selected ready Windows amd64 UE4SS DLL extension provides the Source RCON plan. Chat requests SHALL validate a type from 0 through 7, 1–1024 UTF-8 message bytes, and an optional 17-digit SteamID64 before Platform formats the DLL-supported `SendChat` command. Raw commands SHALL be non-empty UTF-8, contain no NUL/newline control framing, and fit within the declared Source RCON packet bound.
|
||||
|
||||
#### Scenario: Authorized chat dispatch is queued
|
||||
- **WHEN** an authorized operator submits a valid broadcast or targeted chat request for a compatible ready SCUM server
|
||||
- **THEN** Platform creates one scoped `remote.run.rcon.command` job with a frozen Source RCON plan and returns only safe queued state.
|
||||
|
||||
#### Scenario: Unsupported command request is rejected before dispatch
|
||||
- **WHEN** a request has malformed chat data, an unsafe raw command, an undeclared RCON capability, an unpublished extension, or a non-Windows endpoint
|
||||
- **THEN** Platform rejects it without creating a job or retaining command text.
|
||||
|
||||
### Requirement: Raw RCON input is transient and one-time
|
||||
Platform SHALL hold raw RCON command text only in a bounded in-memory one-time broker keyed by the dispatch job. The persisted job, job assignment, browser DTOs, audit events, and result messages SHALL omit command text, chat text, source responses, host paths, and RCON credentials. RCON command jobs SHALL have one attempt and SHALL not automatically retry.
|
||||
|
||||
#### Scenario: Active Run lease consumes a command once
|
||||
- **WHEN** the active leased Run attempt requests its RCON input
|
||||
- **THEN** Platform returns the command once and removes it from the broker.
|
||||
|
||||
#### Scenario: Repeated, expired, or restarted delivery fails closed
|
||||
- **WHEN** a broker payload was already consumed, expired, or lost after a Platform restart
|
||||
- **THEN** a later Run input request fails safely and does not replay the command.
|
||||
|
||||
### Requirement: Only the active signed Run attempt receives RCON input
|
||||
Platform SHALL expose RCON command input only through a signed Run-only route after validating the endpoint, session, job ID, lease token, attempt, scoped server, RCON capability, and frozen Source RCON plan. Browser and plugin APIs SHALL never receive the RCON input, password, host address, or generated local config path.
|
||||
|
||||
#### Scenario: Stale or foreign lease cannot read a command
|
||||
- **WHEN** a Run input request has a wrong endpoint, session, lease token, attempt, or job capability
|
||||
- **THEN** Platform denies it and leaves a valid unconsumed broker payload intact.
|
||||
|
||||
### Requirement: Management console provides direct chat and command controls
|
||||
The server management surface SHALL render direct chat and raw-command controls only through the typed Platform API. It SHALL not request a secondary confirmation, retain a command transcript, expose RCON connection material, or show raw Source RCON replies.
|
||||
|
||||
#### Scenario: Console sends a chat without creating history
|
||||
- **WHEN** an authorized operator submits a valid chat form
|
||||
- **THEN** the console displays the safe dispatch status and does not render the chat text as a durable command record.
|
||||
@@ -0,0 +1,22 @@
|
||||
## 1. Platform one-time command contracts
|
||||
|
||||
- [x] 1.1 Add typed Source RCON plan, chat/raw-command request, safe dispatch response, and bounded validators without exposing command or secret values in persisted job structures.
|
||||
- [x] 1.2 Resolve a selected ready SCUM UE4SS extension into a Windows-only frozen plan; queue one-attempt RCON jobs through a TTL-bounded in-memory broker with no per-command audit record.
|
||||
- [x] 1.3 Add the signed active-lease Run input contract, API route, DTOs, safe error behavior, and focused Platform tests for authorization, one-time consume, rejection, and redaction.
|
||||
|
||||
## 2. Independent Run Source RCON execution
|
||||
|
||||
- [x] 2.1 Mirror the frozen plan and one-time input protocol; add Platform client and Worker plumbing that keeps raw command text out of job journals.
|
||||
- [x] 2.2 Implement scoped managed-config parsing, Windows loopback validation, bounded Source RCON authentication/packet exchange, response redaction, and safe failure codes; correct generated UE4SS config to use `bind_address`.
|
||||
- [x] 2.3 Add Run tests for successful auth/command, source error, malformed/unsafe config or packets, at-most-once input, and non-Windows rejection.
|
||||
|
||||
## 3. Plugin and management console
|
||||
|
||||
- [x] 3.1 Declare the SCUM local lifecycle RCON capability and add manifest coverage without activating the unpublished DLL release.
|
||||
- [x] 3.2 Add typed frontend client/schema contracts and a direct chat/raw-command server-detail panel with no confirmation, transcript, secret, or source-response display.
|
||||
- [x] 3.3 Add focused frontend rendering/submission tests and confirm safe projections exclude RCON material.
|
||||
|
||||
## 4. Verification and delivery
|
||||
|
||||
- [x] 4.1 Run Platform, plugin, frontend, and Run tests; run `openspec validate add-scum-source-rcon-transport --strict` and `scripts/check-structure.sh`.
|
||||
- [x] 4.2 Review scoped diffs, stage only task files in the browser and independent Run repositories, commit, and push both configured branches.
|
||||
Reference in New Issue
Block a user