Make the linux host-setup scripts refuse more than one action - #776
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request makes the Linux host-setup shell scripts enforce a strict “single action” CLI contract (refusing when more than one action is provided), aligning behavior with the existing Windows tooling and preventing unsafe “last action wins” argument handling.
Changes:
- Updated
parse_args()in the Linux host-setup entrypoints to collect action flags anddiewhen more than one is provided. - Ensured
parse_args()returns success on the default/no-action path to keep defaults reachable underset -e. - Updated docs/notes to reflect the new contract (including removing the now-obsolete Linux/Windows difference note).
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
host-setup/bootstrap.sh |
Collects actions and refuses multi-action invocations; preserves interactive/no-terminal default behavior safely under set -e. |
host-setup/linux/install-tools.sh |
Enforces single-action selection; keeps --sudo-timestamp “no tool args” refusal checked after full arg parse. |
host-setup/linux/setup-github.sh |
Enforces single-action selection for --status/--configure while preserving the default status mode. |
host-setup/linux/upgrade-host.sh |
Enforces single-action selection for --status/--packages/--release while preserving the default packages mode. |
host-setup/windows/README.md |
Removes the Linux/Windows “last one wins vs name one” differences-table row since the divergence no longer exists. |
TODO.md |
Updates tracking entry to reflect the broadened scope and adds the new issue link reference. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (4)
host-setup/linux/setup-github.sh:634
actionsis validated by raw count, so repeating the same action flag (e.g.,--status --status) will be refused as “more than one action”, even though it’s not ambiguous. The Windows scripts treat actions as a set of distinct switches ($ACTIONS.Keys), so duplicates can’t cause a multi-action refusal. Deduplicating before enforcing the single-action rule would better match the intended contract.
# The order the actions were given is not a contract, so more than one is a refusal rather than the last one winning.
if ((${#actions[@]} > 1)); then
die "More than one action given (${actions[*]}), name one"
fi
[[ ${#actions[@]} -eq 1 ]] && MODE="${actions[0]}"
host-setup/linux/upgrade-host.sh:611
- As written, the single-action validation will refuse repeated occurrences of the same action (e.g.,
--packages --packages) because it counts flags, not distinct actions. If the contract is “name one action”, it’s more accurate to refuse only when different actions are present, and allow duplicates as harmless repeats (matching the WindowsResolve-Modebehavior).
# The order the actions were given is not a contract, so more than one is a refusal rather than the last one winning.
if ((${#actions[@]} > 1)); then
die "More than one action given (${actions[*]}), name one"
fi
[[ ${#actions[@]} -eq 1 ]] && MODE="${actions[0]}"
host-setup/linux/install-tools.sh:1296
- The multi-action refusal uses the raw length of
actions, so repeating an action flag (e.g.,--report --report) will be treated as “more than one action given” even though it’s unambiguous. If the intent is to forbid different actions, consider deduplicating the collected actions before validating so redundant repeats don’t become a breaking CLI change.
# The order the actions were given is not a contract, so more than one is a refusal rather than the last one winning.
if ((${#actions[@]} > 1)); then
die "More than one action given (${actions[*]}), name one"
fi
[[ ${#actions[@]} -eq 1 ]] && MODE="${actions[0]}"
host-setup/bootstrap.sh:292
- The multi-action refusal currently triggers whenever more than one action flag is present, even if the same action is repeated (e.g.,
--report --report). WindowsResolve-Modecounts distinct actions via$ACTIONS.Keys, so repeated switches don’t become a refusal. Consider deduplicatingactionsbefore enforcing the single-action contract so redundant repeats remain harmless and the error message reflects distinct actions only.
# The order the actions were given is not a contract, so more than one is a refusal rather than the last one winning.
if ((${#actions[@]} > 1)); then
die "More than one action given (${actions[*]}), name one"
fi
[[ ${#actions[@]} -eq 1 ]] && MODE="${actions[0]}"
… Fix (#786) Promote `develop` to `main`, carrying: - #783 Drop IGNORE_GITHUB_REF From the Hosted Get-Version Task (the hosted task follows WORKFLOW.md D3.1 like the inline get-version job already does) - #778 Name the Executable Asset for Its Project and Record the PhotoCleaner Pilot (the executable default names its archive for the project file, the publish-release snippet and doc stub carry explicit permissions, PhotoCleaner ticked as the stage 2 and 4 pilot) - #775 Record 2.0.352 in the Reusable-Workflow Rollout and Add Its Catalog Snippets - #773 Expand references/ in large skill files for progressive disclosure - #776 Make the linux host-setup scripts refuse more than one action - #782 Add PowerShell as an Optional Tool From the Microsoft Feed The release that follows is the pin PhotoCleaner's Dependabot bumps to, and PhotoCleaner's next release through it is the proof that the executable asset is named `PhotoCleaner.7z` again. Closes #769.
Fixes #767. Supersedes the last-command-wins behavior with the strict single-action contract the Windows tooling already enforces.
What changed
The Linux host-setup scripts (
bootstrap.sh,install-tools.sh,setup-github.sh,upgrade-host.sh) overwroteMODEin the argument loop, so the last action given won. That silently discards an intent in the dangerous direction:--report --installdrops the safe action and keeps the one that changes the host.Each script now collects the actions it is given and refuses when more than one is named, mirroring the Windows
Resolve-Moderefusal:The
parse_argsfunctions alsoreturn 0on the no-action/default path, which keeps the default action reachable underset -e.Files
host-setup/bootstrap.sh- actions collected and refused when more than one; help now says "Actions, name one"host-setup/linux/install-tools.sh- same, and the--sudo-timestamptool-name refusal reworded against the resolved actionhost-setup/linux/setup-github.sh- samehost-setup/linux/upgrade-host.sh- samehost-setup/windows/README.md- the "Actions, the last one given wins | Actions, name one" differences-table row is deleted rather than keptTODO.md- the Align the linux host-setup scripts onto 'name one action' instead of 'the last one given wins' #673 entry is broadened to carry the loader (host-setup/linux should do strict CLI validation #767), with a refreshed check anchorVerification
bash -nandshellcheckclean on all four scriptspython3 -m unittest discover -s scripts/tests- 686 tests pass