Skip to content

Add container upgrade command#1943

Open
Saviollage wants to merge 6 commits into
apple:mainfrom
Saviollage:upgrade-command
Open

Add container upgrade command#1943
Saviollage wants to merge 6 commits into
apple:mainfrom
Saviollage:upgrade-command

Conversation

@Saviollage

@Saviollage Saviollage commented Jul 13, 2026

Copy link
Copy Markdown

Type of Change

  • New feature

Motivation and Context

Fixes #1942.

Upgrading container currently requires the update-container.sh shell
script installed under /usr/local/bin. This PR adds a native, discoverable
container upgrade command with behavioral parity to the script:

  • refuses to run while com.apple.container.* services are running and
    directs the user to container system stop
  • resolves the latest release (or a pinned one via -v/--release) from the
    GitHub releases API
  • exits successfully when already on the target version unless -f/--force
  • prefers the signed installer package, asking for confirmation before
    falling back to an unsigned one
  • installs via sudo installer -pkg <pkg> -target / (trust anchored in
    macOS Installer/Gatekeeper validating the signed package, as with the
    script)

The release-resolution and asset-selection logic is implemented as pure
functions with unit tests.

Deliberate deviations from the script, for reviewers:

  • The pin option's long form is --release (short -v kept): a subcommand
    --version option would shadow the --version flag subcommands inherit
    from the root command.
  • Errors go to stderr with the CLI's standard Error: prefix (repo
    convention) rather than the script's plain stdout echo; exit codes match.
  • One release fetch for the latest-version path (the script fetches twice),
    and no unsigned-package prompt when the release has no installer asset at
    all (the script prompts before discovering there is nothing to download).
  • No pre-flight "requires admin privileges" notice; sudo prompts when
    installation starts.
  • With -v <installed-version>, the "already on version" answer requires
    the release lookup first (the script answers before fetching), so it
    needs network access.
  • The installed version comes from the CLI's own ReleaseVersion.version()
    rather than parsing container --version output — identical for any
    installed binary.

Non-goals for this PR (possible follow-ups, listed in the issue):
auto-stopping services, semver-aware comparison, --dry-run, download
progress bar.

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

Unit tests cover the GitHub release decoding, endpoint construction, asset
selection precedence, upgrade policy, and argument parsing (make test:
568 tests / 70 suites passing). An integration test verifies the
running-service guard — the only path that can safely run in CI, since
actually installing a package would modify the host. The guard and the
release-not-found path were additionally verified end-to-end against the
debug binary (exit code 1 with the expected messages in both cases).
make fmt is clean and make docs builds. The full integration suite was
not run locally (this environment hits the BUILDING.md ~/Documents vmnet
limitation); relying on CI for that.

--release avoids colliding with the inherited root --version flag
(argument-parser subcommands inherit the root's version option).
Also moves the GitHubRelease JSON decode inside the existing
do/catch so a malformed 200 response is reported as a clean
ContainerizationError instead of a raw DecodingError dump.
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.

[Request]: Add a container upgrade command

1 participant