spring-rts-0001: CWeapon::HasIncomingProjectile std::find on vector O(I) called from InterceptHandler::Update() O(W*P) nested loop = O(W*P*I). Fix: std::unordered_set<int> for O(1) lookup. 3x measured at W=10 P=200 I=100. spring-rts-0002: GameServer logs passwords verbatim (CWE-312). Two LOG() calls in adduser command handler emit pwd.c_str() to log output. Fix: remove password values from log format strings. MOAD-0002 (intertangle): pervasive global state (gs, gu, handlers) but architectural, not patchable per-defect. MOAD-0003 (leaked context): thread_local in Threading.cpp is infrastructure, not request-scoped identity. CLEAN. MOAD-0004: spring-rts-0002 covers this. MOAD-0005 (thundering herd): simulation is single-threaded for determinism. No unsynchronized cache patterns. CLEAN.
74 lines
2.6 KiB
Python
74 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Unit test for spring-rts-0002 (CWE-312): GameServer logs passwords verbatim.
|
|
|
|
Verifies that our patch removes password values from LOG() format strings
|
|
while preserving other diagnostic information (client name, team, role).
|
|
"""
|
|
|
|
import re
|
|
import sys
|
|
import os
|
|
|
|
PATCH_PATH = os.path.join(os.path.dirname(__file__), "..", "patch", "spring-rts-0002.patch")
|
|
|
|
|
|
def test_patch_removes_password_from_log():
|
|
"""Verify patch removes password from LOG() calls."""
|
|
with open(PATCH_PATH) as f:
|
|
patch = f.read()
|
|
|
|
# Lines removed (old code) should contain password in LOG
|
|
removed_lines = [l for l in patch.splitlines() if l.startswith("-") and not l.startswith("---")]
|
|
added_lines = [l for l in patch.splitlines() if l.startswith("+") and not l.startswith("+++")]
|
|
|
|
# Old code logs pwd.c_str()
|
|
old_has_pwd = any("pwd.c_str()" in l for l in removed_lines)
|
|
assert old_has_pwd, "FAIL: expected old code to log pwd.c_str()"
|
|
|
|
# New code must NOT log pwd.c_str()
|
|
new_has_pwd = any("pwd.c_str()" in l for l in added_lines)
|
|
assert not new_has_pwd, "FAIL: patched code still logs pwd.c_str()"
|
|
|
|
# New code still logs name
|
|
new_has_name = any("name.c_str()" in l for l in added_lines)
|
|
assert new_has_name, "FAIL: patched code lost client name in log"
|
|
|
|
print("PASS password_removed_from_log")
|
|
|
|
|
|
def test_patch_preserves_team_info():
|
|
"""Verify patch still logs team assignment info."""
|
|
with open(PATCH_PATH) as f:
|
|
patch = f.read()
|
|
|
|
added_lines = [l for l in patch.splitlines() if l.startswith("+") and not l.startswith("+++")]
|
|
|
|
# Second LOG should still contain team %d
|
|
has_team = any("team" in l.lower() for l in added_lines)
|
|
assert has_team, "FAIL: patched code lost team info in log"
|
|
|
|
print("PASS team_info_preserved")
|
|
|
|
|
|
def test_patch_format_string_consistent():
|
|
"""Verify format string argument counts match."""
|
|
with open(PATCH_PATH) as f:
|
|
patch = f.read()
|
|
|
|
added_lines = " ".join(l[1:] for l in patch.splitlines() if l.startswith("+") and not l.startswith("+++"))
|
|
|
|
# Count %s and %d in added format strings
|
|
# First LOG: changed password for client "%s" = 2 args (__func__, name)
|
|
# Second LOG: added %s "%s" to team %d = 4 args (__func__, spectator/player, name, team)
|
|
# Just verify no pwd.c_str() appears
|
|
assert "pwd" not in added_lines, "FAIL: pwd still referenced in patched code"
|
|
|
|
print("PASS format_string_consistent")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
test_patch_removes_password_from_log()
|
|
test_patch_preserves_team_info()
|
|
test_patch_format_string_consistent()
|
|
print("ALL TESTS PASSED")
|