diff --git a/src/cli/cli.c b/src/cli/cli.c index 37cb397d89..81a4f2ac21 100644 --- a/src/cli/cli.c +++ b/src/cli/cli.c @@ -11498,18 +11498,29 @@ int cbm_cmd_update(int argc, char **argv) { } printf("codebase-memory-mcp update (current: %s)\n\n", CBM_VERSION); #ifdef _WIN32 + /* The printed command deliberately carries NO execution-policy override. + * A policy-bypass invocation is one of the most heavily weighted + * malicious-script patterns there is, and emitting it as a literal put + * that signature inside every Windows artifact we distribute — to save + * the user one documented step. Pointing at Unblock-File reaches the + * same outcome and leaves the policy decision with them. README's + * Windows install section carries the override for the + * restricted-policy case: documentation is the right place to hand out + * that incantation, a shipped binary is not. */ printf("The update runs from install.ps1, not from this process. Close any\n" "running sessions, then run\n\n"); if (have_dir) { - printf(" powershell -ExecutionPolicy Bypass -File \"%s\\install.ps1\"\n\n", self_dir); + printf(" powershell -File \"%s\\install.ps1\"\n\n", self_dir); } else { - printf(" powershell -ExecutionPolicy Bypass -File install.ps1\n" + printf(" powershell -File install.ps1\n" " (ships in the release archive, and is placed beside the\n" " binary on install)\n\n"); } printf("It downloads the latest release, verifies its checksum, and replaces\n" - "this binary in place. If PowerShell refuses to run the script because\n" - "it came from the internet, Unblock-File it first.\n"); + "this binary in place. If PowerShell refuses to run the script, it is\n" + "usually because the file arrived from the internet: run\n" + "'Unblock-File install.ps1' first. If your execution policy still\n" + "blocks it, the README's Windows install section lists the options.\n"); #else printf("The update runs from install.sh, not from this process. Run\n\n"); if (have_dir) { diff --git a/tests/test_windows_bundle_contract.sh b/tests/test_windows_bundle_contract.sh index 50382ee6d1..430b5ba60c 100644 --- a/tests/test_windows_bundle_contract.sh +++ b/tests/test_windows_bundle_contract.sh @@ -749,9 +749,20 @@ update_windows_block = ( require( update_start >= 0 and "install.ps1" in update_windows_block - and "powershell -ExecutionPolicy Bypass -File" in update_windows_block, + and "powershell -File" in update_windows_block, "cbm_cmd_update must print the install.ps1 command on Windows", ) +# The printed command must NOT carry an execution-policy override. That is a +# canonical malicious-loader pattern, and emitting it as a string literal put +# the signature inside every Windows artifact we ship — to save the user one +# documented step. The hand-off above is the property this contract cares +# about; the bypass flag was only ever the literal form it happened to take. +# Unblock-File covers the common case and the README covers the rest. +require( + "ExecutionPolicy" not in update_windows_block, + "cbm_cmd_update must not print an execution-policy override " + "(document it instead of shipping the pattern in the binary)", +) require( "cbm_windows_launcher" not in cli_source and "windows_launcher_state.h" not in cli_source,