diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-05 14:48:08 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-05 14:48:08 +0200 |
| commit | c11dd22b593358ef7932deec53c8200f5f14ed8b (patch) | |
| tree | f7347edeedb14aef5dafeab6bc3f0263e15b1929 /packages/meshbay-node/tests/test_packaging_win.py | |
| parent | 3fd1f1b456bacc3da2d38323a16b60345ac7105e (diff) | |
| download | meshbay-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/test_packaging_win.py')
| -rw-r--r-- | packages/meshbay-node/tests/test_packaging_win.py | 50 |
1 files changed, 30 insertions, 20 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(): |