Skip to content

feat(update): add self-update command with checksum verification #12

Merged
hectorvent merged 4 commits into
floci-io:mainfrom
juandiii:main
Jul 5, 2026
Merged

feat(update): add self-update command with checksum verification #12
hectorvent merged 4 commits into
floci-io:mainfrom
juandiii:main

Conversation

@juandiii

@juandiii juandiii commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@greptile-apps

greptile-apps Bot commented Jul 3, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds a floci update self-update command that fetches the latest (or a pinned) release binary from GitHub, verifies it against the published sha256sums.txt via a streaming SHA-256 digest, and atomically replaces the running binary using the rename-over trick. A --check flag lets scripts test for staleness without installing.

  • UpdateCommand: resolves the running executable path, guards against Homebrew-managed installs, checks parent-directory writability, downloads the platform-specific asset, streams the checksum without heap-loading the binary, and stages + atomically renames to replace the binary.
  • ReleaseChannel: provides env-overridable GitHub API and download base URLs, making the flow testable against a local server.
  • FlociCli: registers UpdateCommand in the subcommand list.

Confidence Score: 5/5

Safe to merge — the update flow is well-guarded with checksum verification, atomic replacement, and correct cleanup paths throughout.

The three changed files are self-contained: registration in FlociCli is trivial, ReleaseChannel is a thin URL factory, and UpdateCommand handles all the meaningful logic. The atomic rename trick is implemented correctly, staged-file cleanup is properly placed in a catch block, directory (not binary) writability is checked, and the SHA-256 is computed incrementally. Only minor polish items remain.

No files require special attention.

Important Files Changed

Filename Overview
src/main/java/io/floci/cli/commands/UpdateCommand.java New self-update command: downloads platform binary from GitHub releases, verifies SHA-256 checksum via streaming DigestInputStream, and atomically replaces the running binary. Previous-thread issues (directory-only write check, staged-file cleanup, heap-loading checksum) are all addressed in this version.
src/main/java/io/floci/cli/update/ReleaseChannel.java Utility class that constructs GitHub API and release-asset URLs; both are env-overridable for testing and air-gapped setups. Simple and correct.
src/main/java/io/floci/cli/FlociCli.java One-line registration of UpdateCommand in the subcommand list; no issues.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant UpdateCommand
    participant GitHub API
    participant GitHub CDN

    User->>UpdateCommand: floci update [--check] [--version X]
    UpdateCommand->>GitHub API: GET /repos/floci-io/floci-cli/releases/latest
    GitHub API-->>UpdateCommand: {tag_name: "0.1.9"}
    UpdateCommand->>UpdateCommand: compare target vs current version
    alt versions equal
        UpdateCommand-->>User: ✓ floci 0.1.9 is up to date (exit 0)
    else "update available & --check"
        UpdateCommand-->>User: update available (exit 1)
    else update available
        UpdateCommand->>UpdateCommand: resolveSelf(), requireNotBrewManaged(), requireWritable()
        UpdateCommand->>UpdateCommand: detectPlatform() → e.g. darwin-arm64
        UpdateCommand->>GitHub CDN: GET /releases/download/0.1.9/floci-darwin-arm64
        GitHub CDN-->>UpdateCommand: binary (streamed to temp dir)
        UpdateCommand->>GitHub CDN: GET /releases/download/0.1.9/sha256sums.txt
        GitHub CDN-->>UpdateCommand: checksums file
        UpdateCommand->>UpdateCommand: verifyChecksum() via DigestInputStream
        UpdateCommand->>UpdateCommand: replaceAtomically() — stage + ATOMIC_MOVE
        UpdateCommand-->>User: ✓ updated 0.1.8 → 0.1.9 (exit 0)
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant UpdateCommand
    participant GitHub API
    participant GitHub CDN

    User->>UpdateCommand: floci update [--check] [--version X]
    UpdateCommand->>GitHub API: GET /repos/floci-io/floci-cli/releases/latest
    GitHub API-->>UpdateCommand: {tag_name: "0.1.9"}
    UpdateCommand->>UpdateCommand: compare target vs current version
    alt versions equal
        UpdateCommand-->>User: ✓ floci 0.1.9 is up to date (exit 0)
    else "update available & --check"
        UpdateCommand-->>User: update available (exit 1)
    else update available
        UpdateCommand->>UpdateCommand: resolveSelf(), requireNotBrewManaged(), requireWritable()
        UpdateCommand->>UpdateCommand: detectPlatform() → e.g. darwin-arm64
        UpdateCommand->>GitHub CDN: GET /releases/download/0.1.9/floci-darwin-arm64
        GitHub CDN-->>UpdateCommand: binary (streamed to temp dir)
        UpdateCommand->>GitHub CDN: GET /releases/download/0.1.9/sha256sums.txt
        GitHub CDN-->>UpdateCommand: checksums file
        UpdateCommand->>UpdateCommand: verifyChecksum() via DigestInputStream
        UpdateCommand->>UpdateCommand: replaceAtomically() — stage + ATOMIC_MOVE
        UpdateCommand-->>User: ✓ updated 0.1.8 → 0.1.9 (exit 0)
    end
Loading

Reviews (2): Last reviewed commit: "fix(update): harden self-update checksum..." | Re-trigger Greptile

Comment thread src/main/java/io/floci/cli/commands/UpdateCommand.java
Comment thread src/main/java/io/floci/cli/commands/UpdateCommand.java
Comment thread src/main/java/io/floci/cli/commands/UpdateCommand.java
Comment thread src/main/java/io/floci/cli/commands/UpdateCommand.java
@hectorvent
hectorvent merged commit 235be41 into floci-io:main Jul 5, 2026
3 checks passed
hectorvent added a commit that referenced this pull request Jul 7, 2026
…elf-update (#14)

* docs: add AGENTS.md, CONTRIBUTING.md, PR template; document GCP and self-update

- AGENTS.md (tracked): canonical agent guidance — architecture incl. the
  three product trees table, doctor check structure per tree, native-image
  constraints, code style rules, updated scope rules (self-update now in
  scope, must never auto-run)
- CONTRIBUTING.md: build/test setup, Conventional Commits, hand-maintained
  Keep-a-Changelog policy, PR guidelines, tag-driven release process
- .github/pull_request_template.md: adapted from the server repo with a
  'product trees affected' checklist
- README: document the floci gcp command group (quick start, command
  reference, global flags, gcp env variables, CI usage), floci update,
  Java 25+ fat-JAR requirement; drop the unwired snapshot --message flag
  from examples
- CHANGELOG: backfill [Unreleased] with #12 (self-update) and #11
  (ContainerInfo field alignment); document these docs changes
- release.yml: release notes said the fat JAR needs Java 21+, but it is
  built with --release 25 — corrected to Java 25+

* docs(changelog): use standard Keep a Changelog headings for Unreleased

The Documentation section is not one of the six types defined by Keep a
Changelog 1.1.0. New docs (AGENTS.md, CONTRIBUTING.md, README GCP section)
move under Added; the incorrect Java 21+ runtime claim moves under Fixed.
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