From 42b845e2c79b8673f158b9b25c3e210be4be57ae Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 16 Oct 2026 11:00:35 -0700 Subject: [PATCH 1/4] Reject a Dash-Prefixed Agents Name in Both Bootstrap Loaders Fixes #3129 Co-Authored-By: Claude Sonnet 5.5 --- host-setup/bootstrap.ps1 | 3 +++ host-setup/bootstrap.sh | 1 + tests/test_bootstrap.py | 16 ++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/host-setup/bootstrap.ps1 b/host-setup/bootstrap.ps1 index 71b722e5..e6f2660e 100644 --- a/host-setup/bootstrap.ps1 +++ b/host-setup/bootstrap.ps1 @@ -488,6 +488,9 @@ function Invoke-Upgrade { # Installs only what is named, since the agent tools are never installed as a set nobody chose. function Invoke-AgentsInstall { if ($script:AGENT_NAMES.Count -eq 0) { die "-Agents takes the tools to install, separated by commas, or 'all'" } + foreach ($name in $script:AGENT_NAMES) { + if ($name.StartsWith('-')) { die "-Agents takes tool names, and '$name' starts with a dash" } + } if ($script:AGENT_NAMES -ccontains 'all') { if ($script:AGENT_NAMES.Count -gt 1) { die "-Agents takes 'all' alone, or a list of tool names" } Invoke-Tool -Tool 'install-agents.ps1' -Arguments '-Install', '-All' diff --git a/host-setup/bootstrap.sh b/host-setup/bootstrap.sh index 90f9796b..911164b4 100755 --- a/host-setup/bootstrap.sh +++ b/host-setup/bootstrap.sh @@ -409,6 +409,7 @@ parse_args() { IFS=',' read -r -a agent_fields <<<"$2" for agent_name in "${agent_fields[@]}"; do if [[ -n $agent_name ]]; then + [[ $agent_name != -* ]] || die "--agents takes tool names, and \"$agent_name\" starts with a dash" AGENTS+=("$agent_name") if [[ $agent_name == "all" ]]; then saw_all=true diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index ac1fe7f4..618910c3 100755 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -1795,6 +1795,14 @@ def test_agents_with_an_empty_list_is_refused_before_anything_runs(self) -> None self.assertEqual(self.steps(), []) self.assertEqual(list(self.data.iterdir()), []) + def test_agents_a_dash_prefixed_name_is_refused_before_anything_runs(self) -> None: + for given in ("--all", "-a", "herdr,--all", "-x,herdr"): + with self.subTest(given=given): + result = self.run_main(action="--agents", args=(given,)) + self.assertNotEqual(result.returncode, 0) + self.assertIn("starts with a dash", result.stderr) + self.assertEqual(self.steps(), []) + def test_agents_with_no_list_is_refused_before_anything_runs(self) -> None: result = self.run_main(action="--agents") self.assertNotEqual(result.returncode, 0) @@ -1972,6 +1980,14 @@ def test_empty_names_are_dropped_from_the_list(self) -> None: self.assertEqual(result.returncode, 0, result.stderr) self.assertEqual(self.steps(), ["install-agents.ps1 -Install herdr cswap"], result.stdout) + def test_a_dash_prefixed_name_is_refused(self) -> None: + for given in ("-All", "-a", "herdr,-All"): + with self.subTest(given=given): + result = self.run_agents([given]) + self.assertNotEqual(result.returncode, 0) + self.assertIn("starts with a dash", result.stderr) + self.assertEqual(self.steps(), []) + def test_an_empty_list_is_refused(self) -> None: result = self.run_agents([","]) self.assertNotEqual(result.returncode, 0) From 0fd1f60da0d8a2af9a5a5ebe95c3859d530a9aaf Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 16 Oct 2026 11:06:36 -0700 Subject: [PATCH 2/4] Refuse an En or Em Dash Before an Agents Name Too PowerShell binds a typographic dash as a parameter prefix. Co-Authored-By: Claude Sonnet 5.5 --- host-setup/bootstrap.ps1 | 2 +- tests/test_bootstrap.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/host-setup/bootstrap.ps1 b/host-setup/bootstrap.ps1 index e6f2660e..0a1d0878 100644 --- a/host-setup/bootstrap.ps1 +++ b/host-setup/bootstrap.ps1 @@ -489,7 +489,7 @@ function Invoke-Upgrade { function Invoke-AgentsInstall { if ($script:AGENT_NAMES.Count -eq 0) { die "-Agents takes the tools to install, separated by commas, or 'all'" } foreach ($name in $script:AGENT_NAMES) { - if ($name.StartsWith('-')) { die "-Agents takes tool names, and '$name' starts with a dash" } + if ($name -match '^[-\u2013\u2014\u2015]') { die "-Agents takes tool names, and '$name' starts with a dash" } } if ($script:AGENT_NAMES -ccontains 'all') { if ($script:AGENT_NAMES.Count -gt 1) { die "-Agents takes 'all' alone, or a list of tool names" } diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index 618910c3..57692027 100755 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -1981,7 +1981,7 @@ def test_empty_names_are_dropped_from_the_list(self) -> None: self.assertEqual(self.steps(), ["install-agents.ps1 -Install herdr cswap"], result.stdout) def test_a_dash_prefixed_name_is_refused(self) -> None: - for given in ("-All", "-a", "herdr,-All"): + for given in ("-All", "-a", "herdr,-All", "\u2013All", "herdr,\u2014y"): with self.subTest(given=given): result = self.run_agents([given]) self.assertNotEqual(result.returncode, 0) From 0586063053fed46e2b6a438607e8a707775ae8ca Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 16 Oct 2026 11:11:53 -0700 Subject: [PATCH 3/4] Pin the Horizontal Bar Dash in the PowerShell Agents Test Co-Authored-By: Claude Sonnet 5.5 --- tests/test_bootstrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index 57692027..2de4105a 100755 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -1981,7 +1981,7 @@ def test_empty_names_are_dropped_from_the_list(self) -> None: self.assertEqual(self.steps(), ["install-agents.ps1 -Install herdr cswap"], result.stdout) def test_a_dash_prefixed_name_is_refused(self) -> None: - for given in ("-All", "-a", "herdr,-All", "\u2013All", "herdr,\u2014y"): + for given in ("-All", "-a", "herdr,-All", "\u2013All", "herdr,\u2014y", "\u2015All"): with self.subTest(given=given): result = self.run_agents([given]) self.assertNotEqual(result.returncode, 0) From 27296acdee90431a3ab2a1aca56eeb25beb55ec4 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 16 Oct 2026 11:15:42 -0700 Subject: [PATCH 4/4] Assert No Fetch Happens Before a Dash-Prefixed Agents Name Is Refused Co-Authored-By: Claude Sonnet 5.5 --- tests/test_bootstrap.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index 2de4105a..8825d352 100755 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -1802,6 +1802,7 @@ def test_agents_a_dash_prefixed_name_is_refused_before_anything_runs(self) -> No self.assertNotEqual(result.returncode, 0) self.assertIn("starts with a dash", result.stderr) self.assertEqual(self.steps(), []) + self.assertEqual(list(self.data.iterdir()), []) def test_agents_with_no_list_is_refused_before_anything_runs(self) -> None: result = self.run_main(action="--agents")