Skip to content

(feat): adding update command - #9

Merged
AaronCQL merged 18 commits into
mainfrom
pavs/update-command
Mar 24, 2026
Merged

(feat): adding update command#9
AaronCQL merged 18 commits into
mainfrom
pavs/update-command

Conversation

@lifeofpavs

@lifeofpavs lifeofpavs commented Mar 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds jup update — a self-update command that fetches and runs install.sh from the matching release tag, which handles volta/npm/binary detection and installation internally.

Update command

  • jup update — fetches install.sh from the release tag URL, writes it to a secure temp directory (mkdtemp), and executes it
  • jup update --check — reports whether an update is available without installing
  • Version detection via GitHub REST API (/repos/jup-ag/cli/releases/latest)
  • Supports both JSON and table output formats

install.sh hardening

1. Secure temp file creation

The original script wrote to a predictable path (/tmp/jup), which is vulnerable to symlink attacks — an attacker could place a symlink at /tmp/jup pointing to another file, and the script would overwrite it. The fix uses mktemp -d for a unique temp directory and trap for cleanup:

TMP_DIR=$(mktemp -d)
TMP_BINARY="${TMP_DIR}/${BINARY}"
trap 'rm -rf "$TMP_DIR"' EXIT

2. Checksum grep error handling

Under set -e, if grep finds no matching checksum line it returns exit code 1, killing the script with no useful message. The fix suppresses the exit and provides an actionable error:

EXPECTED=$(grep "$ASSET" "$TMP_CHECKSUMS" | awk '{print $1}') || true
if [ -z "$EXPECTED" ]; then
  error "No checksum found for $ASSET in checksums.txt"
fi

…ksum parsing

- Switch getLatestVersion to GitHub REST API JSON response instead of redirect parsing
- Replace identity maps in getBinaryAssetName with Set-based validation
- Parse checksum line once and reuse; compute Buffer.from(binary) once
ky sends the runtime's default User-Agent automatically; GitHub only
rejects requests with an empty header, not a missing one.
Single-use method with no reuse benefit; inlining reduces indirection.
Fetch checksums before the binary to validate platform support
dynamically instead of hardcoding allowed platforms/archs.
Both npm and binary paths now run automatically. Removes the
manual_update_required status — all updates return status: updated.
@lifeofpavs
lifeofpavs marked this pull request as ready for review March 20, 2026 17:33
@lifeofpavs
lifeofpavs requested a review from AaronCQL March 20, 2026 17:33
Ship install.sh as a GitHub release asset and fetch it from the
release URL instead of raw.githubusercontent.com, so the update
command uses the same versioned script that users install with.
Comment thread src/commands/UpdateCommand.ts Fixed

try {
const script = await ky.get(scriptUrl).text();
await writeFile(scriptPath, script);

Check failure

Code scanning / CodeQL

Insecure temporary file High

Insecure creation of file in the os temp dir.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Addressed in a follow-up. The updater now creates a unique temp directory with mkdtemp(...), writes install.sh inside that directory with mode 0o700, and removes the directory in finally, so the predictable temp-file path is gone.

Avoid predictable temp file path by creating a unique directory with
mkdtemp, preventing symlink attacks flagged by GitHub code scanning.
The script is already in the repo — import it as text so Bun bundles
it into the compiled binary. Removes the runtime network fetch.
Revert the text import approach — fetching from the release URL is
cleaner than importing a shell script as a TS text module.
Remove install method detection, package manager commands, and binary
update logic. The update command now fetches and runs install.sh which
handles volta/npm/binary fallback internally.
macOS 15+ ships a native /sbin/sha256sum, so the shasum -a 256
fallback for older versions is unnecessary.
@AaronCQL
AaronCQL merged commit da6e74d into main Mar 24, 2026
4 checks passed
@AaronCQL
AaronCQL deleted the pavs/update-command branch March 24, 2026 03:00
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.

3 participants