feat(facade): append rcon_password as final server.cfg line
Source cvar semantics are last-wins; appending the rcon_password after all overlay exec lines and blueprint config ensures no overlay or user config line can silently override it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
83d2a9932c
commit
2a440dae45
2 changed files with 48 additions and 1 deletions
|
|
@ -44,11 +44,16 @@ def build_server_spec_payload(
|
||||||
for overlay_id, _, expose in reversed(overlay_rows)
|
for overlay_id, _, expose in reversed(overlay_rows)
|
||||||
if expose
|
if expose
|
||||||
]
|
]
|
||||||
|
config_lines: list[str] = exec_lines + json.loads(blueprint.config)
|
||||||
|
# rcon_password is appended LAST so neither overlays nor user blueprint
|
||||||
|
# config can override it (Source's cvar semantics are last-wins).
|
||||||
|
if server.rcon_password:
|
||||||
|
config_lines.append(f'rcon_password "{server.rcon_password}"')
|
||||||
return {
|
return {
|
||||||
"port": server.port,
|
"port": server.port,
|
||||||
"overlays": overlays,
|
"overlays": overlays,
|
||||||
"arguments": json.loads(blueprint.arguments),
|
"arguments": json.loads(blueprint.arguments),
|
||||||
"config": exec_lines + json.loads(blueprint.config),
|
"config": config_lines,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -343,3 +343,45 @@ def test_initialize_fails_fast_on_uncached_workshop_items(
|
||||||
assert all("initialize" not in cmd for cmd in invocations), invocations
|
assert all("initialize" not in cmd for cmd in invocations), invocations
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# build_server_spec_payload — rcon_password injection
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def _make_server_blueprint(rcon: str = "") -> tuple[Server, Blueprint]:
|
||||||
|
bp = Blueprint(
|
||||||
|
id=1, user_id=1, name="bp",
|
||||||
|
arguments='["-tickrate","60"]',
|
||||||
|
config='["sv_consistency 1","mp_gamemode coop"]',
|
||||||
|
)
|
||||||
|
srv = Server(
|
||||||
|
id=1, user_id=1, blueprint_id=1, name="s", port=27500,
|
||||||
|
rcon_password=rcon,
|
||||||
|
)
|
||||||
|
return srv, bp
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_server_spec_payload_appends_rcon_password_last() -> None:
|
||||||
|
from l4d2web.services.l4d2_facade import build_server_spec_payload
|
||||||
|
|
||||||
|
srv, bp = _make_server_blueprint(rcon="topsecret123")
|
||||||
|
overlays = [(7, "/overlays/7", True), (8, "/overlays/8", False)]
|
||||||
|
spec = build_server_spec_payload(srv, bp, overlays)
|
||||||
|
|
||||||
|
cfg = spec["config"]
|
||||||
|
# rcon_password line is the LAST entry — overlay exec lines + blueprint
|
||||||
|
# config + rcon_password.
|
||||||
|
assert cfg[-1] == 'rcon_password "topsecret123"'
|
||||||
|
# Lines before our injection still contain the blueprint config.
|
||||||
|
assert "sv_consistency 1" in cfg
|
||||||
|
assert "mp_gamemode coop" in cfg
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_server_spec_payload_omits_rcon_password_when_empty() -> None:
|
||||||
|
from l4d2web.services.l4d2_facade import build_server_spec_payload
|
||||||
|
|
||||||
|
srv, bp = _make_server_blueprint(rcon="")
|
||||||
|
spec = build_server_spec_payload(srv, bp, [])
|
||||||
|
for line in spec["config"]:
|
||||||
|
assert not line.startswith("rcon_password ")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue