aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/tests
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-05 14:48:08 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-05 14:48:08 +0200
commitc11dd22b593358ef7932deec53c8200f5f14ed8b (patch)
treef7347edeedb14aef5dafeab6bc3f0263e15b1929 /packages/meshbay-node/tests
parent3fd1f1b456bacc3da2d38323a16b60345ac7105e (diff)
downloadmeshbay-c11dd22b593358ef7932deec53c8200f5f14ed8b.tar.gz
fix(node): register the service-mode task with Register-ScheduledTask -LogonType S4U
schtasks.exe has no flag naming the logon type directly -- it only infers S4U vs Interactive from whether /rp is present, and both readings broke live on a blank-password account: /rp "" fails schtasks' own credential validation, and omitting /rp registers "Interactive only", which never launches the process at boot or on demand despite installing cleanly. Register-ScheduledTask -LogonType S4U names the logon type explicitly, no inference. Confirmed live: install, manual start, and unattended boot-time start all now work. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node/tests')
-rw-r--r--packages/meshbay-node/tests/test_packaging_win.py50
-rw-r--r--packages/meshbay-node/tests/test_platform.py43
2 files changed, 68 insertions, 25 deletions
diff --git a/packages/meshbay-node/tests/test_packaging_win.py b/packages/meshbay-node/tests/test_packaging_win.py
index 0cf6367..df5a24f 100644
--- a/packages/meshbay-node/tests/test_packaging_win.py
+++ b/packages/meshbay-node/tests/test_packaging_win.py
@@ -284,29 +284,39 @@ def test_service_ps1_and_service_mode_ps1_are_extraresources():
def test_service_install_uses_s4u_not_a_stored_password():
"""
- schtasks /create ... /ru <user> /rp "" with no /it registers an S4U logon:
- no password stored anywhere, and — unlike LocalSystem/NetworkService — it
- loads this account's own profile, so %LOCALAPPDATA%\\meshbay\\ needs no
- relocation. Losing the empty /rp "" (e.g. "fixing" it into a real prompt
- for a password) would either store a secret or silently stop working.
+ Register-ScheduledTask -LogonType S4U: no password stored anywhere, and
+ — unlike LocalSystem/NetworkService — it loads this account's own
+ profile, so %LOCALAPPDATA%\\meshbay\\ needs no relocation.
+
+ Not `schtasks /create`: schtasks only *infers* the logon type from
+ whether /rp is present, and both readings broke live on a blank-password
+ account (common on a personal PC, 2026-09-05) -- `/rp ""` fails
+ credential validation ("the user name or password is incorrect", even
+ though nothing is wrong), and omitting /rp registers "Interactive only"
+ instead of S4U, which never runs at boot and does not launch anything
+ even run on demand while signed in. -LogonType S4U is explicit, so losing
+ it (e.g. "simplifying" back to schtasks, or dropping -ErrorAction Stop so
+ a permission failure silently falls through to "installed") would
+ reintroduce one of those two live-reproduced failures.
"""
src = (WIN / "service.ps1").read_text(encoding="utf-8")
- # The prose above the actual command is allowed to say "/it" while
- # explaining why it is absent (the same "read the comment, not the
- # directive" trap CLAUDE.md already tracks) -- so check the real
- # invocation line, not the whole file.
- create_line = next(
- (line for line in src.splitlines() if line.strip().startswith("& schtasks")
- and "/create" in line), None)
- assert create_line, "no schtasks /create invocation found"
- tokens = create_line.split()
- assert "/sc" in tokens and tokens[tokens.index("/sc") + 1] == "onstart", (
- "must trigger at boot, not at sign-in (/sc onlogon)")
- assert "/ru" in tokens
- assert "/rp" in tokens and tokens[tokens.index("/rp") + 1] == '""', (
- "must pass an empty run-as password (S4U)")
- assert "/it" not in tokens, "an interactive-token task would need the user signed in"
+ # Isolate the actual "install" case from the docstring above it (which
+ # names these same cmdlets in prose) -- checks below must see only code.
+ lines = src.splitlines()
+ install_start = next(i for i, line in enumerate(lines) if '"install" {' in line)
+ remove_start = next(i for i, line in enumerate(lines) if '"remove" {' in line)
+ install_block = "\n".join(lines[install_start:remove_start])
+
+ assert "New-ScheduledTaskTrigger -AtStartup" in install_block, (
+ "must trigger at boot, not at sign-in")
+ assert "-LogonType S4U" in install_block, (
+ "must request S4U explicitly, not infer it from /rp")
+ assert "Register-ScheduledTask" in install_block
+ assert "-ErrorAction Stop" in install_block, (
+ "a permission failure must throw, not fall through as if it installed")
assert "Get-Credential" not in src, "no password should ever be prompted for"
+ assert "schtasks" not in install_block, (
+ "the install branch must not fall back to schtasks /create")
def test_service_task_name_is_the_same_everywhere():
diff --git a/packages/meshbay-node/tests/test_platform.py b/packages/meshbay-node/tests/test_platform.py
index 91713be..92e74df 100644
--- a/packages/meshbay-node/tests/test_platform.py
+++ b/packages/meshbay-node/tests/test_platform.py
@@ -346,24 +346,57 @@ def test_service_install_removes_the_startup_launcher_first(win_startup, monkeyp
monkeypatch.setattr(plat, "_current_user", lambda: "DOMAIN\\user")
calls = []
monkeypatch.setattr(
- plat, "_schtasks",
- lambda *args: calls.append(args) or Mock(returncode=0, stdout="", stderr=""))
+ plat.subprocess, "run",
+ lambda argv, **kw: calls.append((argv, kw)) or Mock(returncode=0, stdout="", stderr=""))
plat.service_install(exe=r"C:\x\meshbay-node.exe")
assert not win_startup.exists() # removed as part of service_install
- assert calls and calls[0][0] == "/create"
+ assert calls and calls[0][0][0] == "powershell"
+ env = calls[0][1]["env"]
+ assert env["MESHBAY_SVC_USER"] == "DOMAIN\\user"
+ assert env["MESHBAY_SVC_EXE"] == r"C:\x\meshbay-node.exe"
+
+
+def test_service_install_uses_s4u_not_a_stored_password(monkeypatch):
+ """Register-ScheduledTask -LogonType S4U, not schtasks: schtasks only
+ infers the logon type from whether /rp is present, and both readings
+ broke live on a blank-password account (2026-09-05) -- /rp "" fails
+ credential validation, and omitting /rp registers "Interactive only",
+ which never runs at boot or on demand. See platform.py's service mode
+ comment for the full story."""
+ monkeypatch.setattr(plat, "_current_user", lambda: "DOMAIN\\user")
+ calls = []
+ monkeypatch.setattr(
+ plat.subprocess, "run",
+ lambda argv, **kw: calls.append((argv, kw)) or Mock(returncode=0, stdout="", stderr=""))
+
+ plat.service_install(exe=r"C:\x\meshbay-node.exe")
+
+ script = calls[0][0][-1]
+ assert "-LogonType S4U" in script
+ assert "New-ScheduledTaskTrigger -AtStartup" in script
def test_service_install_tolerates_no_startup_launcher_present(win_startup, monkeypatch):
assert not win_startup.exists()
monkeypatch.setattr(plat, "_current_user", lambda: "DOMAIN\\user")
- monkeypatch.setattr(plat, "_schtasks",
- lambda *args: Mock(returncode=0, stdout="", stderr=""))
+ monkeypatch.setattr(plat.subprocess, "run",
+ lambda argv, **kw: Mock(returncode=0, stdout="", stderr=""))
plat.service_install(exe=r"C:\x\meshbay-node.exe") # no error
assert not win_startup.exists()
+def test_service_install_raises_with_powershells_error_message(monkeypatch):
+ monkeypatch.setattr(plat, "_current_user", lambda: "DOMAIN\\user")
+ monkeypatch.setattr(
+ plat.subprocess, "run",
+ lambda argv, **kw: Mock(returncode=1, stdout="", stderr="Access is denied."))
+
+ with pytest.raises(RuntimeError, match="Access is denied"):
+ plat.service_install(exe=r"C:\x\meshbay-node.exe")
+
+
# ── Packaged defaults ────────────────────────────────────────────────────────
def test_frozen_build_finds_default_env_beside_the_executable(monkeypatch, tmp_path):