Skip to content

feat(update): add self-update command#67

Merged
onuryilmaz merged 8 commits into
mainfrom
feat/update-command
Jul 12, 2026
Merged

feat(update): add self-update command#67
onuryilmaz merged 8 commits into
mainfrom
feat/update-command

Conversation

@onuryilmaz

Copy link
Copy Markdown
Contributor

Summary

  • Adds cloudctl update command (closes [FEAT cloudctl] - Self-update capability #53) that queries the GitHub Releases API, downloads the matching .tar.gz for the current OS/arch, verifies the SHA256 checksum, and atomically replaces the running binary via github.com/minio/selfupdate
  • --check flag performs a version check only (no download/install); exits 0 with available status for scripting
  • UpdateStatus / UpdateResult types added to cmd/output; both plain and interactive printers handle the new type

Test plan

  • make build compiles without errors
  • make test — all unit tests in cmd and cmd/output pass (13 new tests in cmd/update_test.go)
  • ./bin/cloudctl update --help renders correct help text
  • ./bin/cloudctl --help shows update in the command list
  • ./bin/cloudctl update --check (requires network) reports current vs latest version
  • ./bin/cloudctl update --check -o json emits machine-readable UpdateResult

Implements `cloudctl update` (closes #53) which queries the GitHub
Releases API for the latest version, downloads the matching .tar.gz
for the current OS/arch, verifies the SHA256 checksum produced by
GoReleaser, extracts the cloudctl binary, and atomically replaces the
running executable via github.com/minio/selfupdate.

- `--check` flag performs a version check only (no download/install)
- `-o json/yaml` produces machine-readable UpdateResult output
- All helper functions have injectable *http.Client variants for unit tests
- 13 unit tests added in cmd/update_test.go
- UpdateStatus/UpdateResult types added to cmd/output
- Plain and interactive printers handle the new UpdateResult type

Signed-off-by: onuryilmaz <onur.yilmaz@sap.com>
Copilot AI review requested due to automatic review settings July 11, 2026 22:11
@onuryilmaz
onuryilmaz requested review from a team as code owners July 11, 2026 22:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds a new cloudctl update CLI command to self-update the running binary by querying GitHub Releases, selecting the OS/arch artifact, verifying a SHA256 checksum, and applying the update using minio/selfupdate. This fits into cloudctl as a user-facing maintenance command alongside sync, cluster-version, and version.

Changes:

  • Introduces cloudctl update with a --check mode for “check only” workflows.
  • Adds UpdateStatus / UpdateResult output types and printer support (plain + interactive).
  • Adds unit tests for GitHub release parsing, checksum parsing, archive extraction, and output formatting.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
go.mod Adds indirect dependencies used by the self-update implementation.
go.sum Records sums for newly introduced dependencies.
cmd/update.go Implements the update command: GitHub release lookup, asset selection, checksum verification, archive extraction, and selfupdate apply.
cmd/update_test.go Adds unit tests for update helpers and output formatting.
cmd/root.go Registers update in help text and adds the command to the root command.
cmd/output/types.go Adds UpdateStatus and UpdateResult output types.
cmd/output/plain_printer.go Adds plain-text rendering for UpdateResult.
cmd/output/interactive_printer.go Adds interactive/TTY rendering for UpdateResult.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/update.go
Comment thread cmd/update.go
Comment thread cmd/update.go
Comment thread cmd/update.go
Comment thread cmd/update.go
Comment thread cmd/update.go
Comment thread cmd/update.go
…guard

- Introduce updateHTTPClient with ResponseHeaderTimeout: 30s so network
  calls cannot hang indefinitely on stalled connections
- Use updateHTTPClient in all three public wrappers (fetchLatestRelease,
  downloadChecksum, downloadAndExtract) instead of http.DefaultClient
- Add User-Agent: cloudctl/<version> header to GitHub API requests
- Guard strings.Fields()[0] in downloadChecksumFrom against empty/
  whitespace-only response bodies to prevent an index-out-of-range panic
- Add TestDownloadChecksum_EmptyBody unit test for the new guard

Signed-off-by: onuryilmaz <onur.yilmaz@sap.com>
Replace bare `defer x.Close()` with `defer func() { _ = x.Close() }()`
on all three resp.Body and the gz.Close defers, matching the pattern
already used in cluster-version.go.

Signed-off-by: onuryilmaz <onur.yilmaz@sap.com>

Copilot AI left a comment

Copy link
Copy Markdown

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 7 out of 8 changed files in this pull request and generated 4 comments.

Comment thread cmd/update.go Outdated
Comment thread cmd/update.go
Comment thread cmd/update.go Outdated
Comment thread cmd/update.go
- Clone http.DefaultTransport for updateHTTPClient so proxy settings,
  TLS config, keep-alives, and HTTP/2 support are preserved
- Validate decoded checksum is exactly sha256.Size (32) bytes before use
- Cap archive download at 256 MiB with io.LimitReader to prevent OOM on
  malicious or unexpectedly large responses
- Reject non-regular tar entries (symlinks, hard links, etc.) matching
  the "cloudctl" name to prevent writing an invalid binary
- Add tests: InvalidLength, NonRegularEntry for the new guards

Signed-off-by: onuryilmaz <onur.yilmaz@sap.com>

Copilot AI left a comment

Copy link
Copy Markdown

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 7 out of 8 changed files in this pull request and generated 4 comments.

Comment thread cmd/update.go Outdated
Comment thread cmd/update.go
Comment thread cmd/output/plain_printer.go
Comment thread cmd/output/interactive_printer.go
…r branches

- Cap downloadChecksumFrom body read at 4 KiB with io.LimitReader to
  prevent memory abuse from unexpectedly large checksum responses
- Use a safe type-assertion for http.DefaultTransport clone; fall back to
  http.DefaultTransport as-is when it is not a *http.Transport to avoid
  a panic if DefaultTransport has been replaced
- Add default branch to plainPrinter and interactivePrinter UpdateResult
  status switches so unknown status values produce visible output

Signed-off-by: onuryilmaz <onur.yilmaz@sap.com>

Copilot AI left a comment

Copy link
Copy Markdown

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 7 out of 8 changed files in this pull request and generated 3 comments.

Comment thread cmd/update.go
Comment thread cmd/update.go
Comment thread cmd/update.go Outdated
- Use golang.org/x/mod/semver for version comparison so that current >=
  latest (pre-release or self-built builds) is reported as up-to-date
  rather than triggering an unintended downgrade; fall back to string
  equality when either version is not valid semver
- Return a clear, actionable error on Windows (releases use .zip archives
  which are not yet supported) with a link to the releases page
- Add Timeout: 10min to updateHTTPClient as a hard upper bound on total
  request time alongside ResponseHeaderTimeout for stalled header phase
- Add golang.org/x/mod v0.38.0 as a direct dependency

Signed-off-by: onuryilmaz <onur.yilmaz@sap.com>

Copilot AI left a comment

Copy link
Copy Markdown

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 7 out of 8 changed files in this pull request and generated 5 comments.

Comment thread cmd/update.go Outdated
Comment thread cmd/update.go
Comment thread cmd/update.go
Comment thread go.mod Outdated
Comment thread go.mod Outdated
…prefix, and direct deps

- Normalize rel.TagName to v-prefix so semver comparison works for tags
  without a leading v (same normalization already applied to currentVersion)
- Add 128 MiB LimitReader guard when reading the cloudctl entry from tar
  to prevent decompression-bomb OOM (distinct from the 256 MiB compressed cap)
- Remove "downloading checksum:" prefix from inner HTTP status error to
  avoid double-wrapping ("downloading checksum: downloading checksum: HTTP 404")
- Run go mod tidy: minio/selfupdate and golang.org/x/mod are now marked
  as direct dependencies since they are imported in cmd/update.go

Signed-off-by: onuryilmaz <onur.yilmaz@sap.com>

Copilot AI left a comment

Copy link
Copy Markdown

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 7 out of 8 changed files in this pull request and generated 1 comment.

Comment thread cmd/update.go
Signed-off-by: onuryilmaz <onur.yilmaz@sap.com>

Copilot AI left a comment

Copy link
Copy Markdown

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 7 out of 8 changed files in this pull request and generated no new comments.

@onuryilmaz
onuryilmaz merged commit 4eed2cb into main Jul 12, 2026
8 checks passed
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.

[FEAT cloudctl] - Self-update capability

2 participants