Skip to content

Make the linux host-setup scripts refuse more than one action - #776

Merged
ptr727 merged 2 commits into
developfrom
feature/strict-cli-validation
Aug 16, 2026
Merged

Make the linux host-setup scripts refuse more than one action#776
ptr727 merged 2 commits into
developfrom
feature/strict-cli-validation

Conversation

@ptr727

@ptr727 ptr727 commented Aug 16, 2026

Copy link
Copy Markdown
Owner

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) overwrote MODE in the argument loop, so the last action given won. That silently discards an intent in the dangerous direction: --report --install drops 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-Mode refusal:

ERROR: More than one action given (report install), name one

The parse_args functions also return 0 on the no-action/default path, which keeps the default action reachable under set -e.

Files

Verification

  • bash -n and shellcheck clean on all four scripts
  • Prose gate, markdownlint, and editorconfig-checker clean
  • python3 -m unittest discover -s scripts/tests - 686 tests pass
  • Manual refusal tests for every multi-action combination, plus single-action and no-action paths

Copilot AI lite review requested due to automatic review settings August 16, 2026 22:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 and die when more than one is provided.
  • Ensured parse_args() returns success on the default/no-action path to keep defaults reachable under set -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.

Copilot AI review requested due to automatic review settings August 16, 2026 23:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

@ptr727
ptr727 requested a lite review from Copilot August 16, 2026 23:11
@ptr727
ptr727 merged commit 83524d8 into develop Aug 16, 2026
9 checks passed
@ptr727
ptr727 deleted the feature/strict-cli-validation branch August 16, 2026 23:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

  • actions is 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 Windows Resolve-Mode behavior).
    # 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). Windows Resolve-Mode counts distinct actions via $ACTIONS.Keys, so repeated switches don’t become a refusal. Consider deduplicating actions before 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]}"

ptr727 added a commit that referenced this pull request Aug 17, 2026
… 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants