Add numan update --self for CLI binary upgrades - #94
Conversation
Standalone installs download the matching GitHub Release asset, verify SHA256SUMS, and replace the binary. Homebrew, winget, and cargo installs print the exact upgrade command instead. Co-authored-by: Anthony Thompson <github@trackdub.com>
|
Warning Review limit reached
Next review available in: 34 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (9)
📝 WalkthroughWalkthroughAdded ChangesSelf-update flow
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 8✅ Passed checks (8 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
Warning Review ran into problems🔥 ProblemsLinked repositories: Public OSS repositories can only analyze public repositories installed in this organization. Analyzed Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@README.md`:
- Around line 286-287: Update the README self-update command descriptions to
clarify that --check only checks for newer binaries on standalone installations,
while Homebrew, winget, and cargo installations instead display the relevant
package-manager upgrade hint; preserve the existing command examples and explain
the managed-install behavior alongside them.
In `@src/cmd/self_update.rs`:
- Around line 592-632: Update src/cmd/self_update.rs#L566-L590 and `#L592-L632`:
add an exe: &Path parameter to execute_with_client, pass the executable from
execute, and use a fixed standalone path such as /usr/local/bin/numan in both
tests instead of skipping based on detect_install_method; populate
FakeClient.files and add apply-path tests covering checksum mismatch, missing
SHA256SUMS, an asset absent from SHA256SUMS, and a missing platform asset.
- Around line 365-371: Update replace_binary_unix to capture the existing
destination binary’s permission mode before write_bytes_atomic, then apply that
mode to the replacement while ensuring the owner-execute bit is set. Change
make_executable or its call path so it no longer unconditionally applies 0o755,
preserving group/other permissions and existing restrictive settings.
- Around line 566-590: Expand the self-update tests around FakeClient by
populating files and injecting the install target so failure paths execute
safely against temporary paths. Add coverage for checksum mismatch, missing or
incomplete SHA256SUMS, missing platform assets, and verify replace_binary
rejects empty bytes without modifying the target. Add tests for
locate_extracted_numan at root, one directory deep, and absent; parse_sha256sums
rejecting short/non-hex hashes; and parse_release_version rejecting malformed
tags.
- Around line 349-362: Update the non-Windows dispatch arm in replace_binary to
use cfg(unix) instead of cfg(not(windows)), matching the predicate on
replace_binary_unix. Keep the Windows branch unchanged.
- Around line 242-254: Move the release_asset_name call out of the initial setup
and place it immediately before the apply/install logic that consumes
asset_name, after the is_newer_than and check-mode early returns. Keep version
and status checks independent of platform asset support so --check reports
up-to-date or available status on every detected platform.
- Around line 374-410: Update replace_binary_windows so the new binary is fully
written and flushed to a temporary file in the destination parent before
renaming dest to the backup. Then install the staged file and preserve rollback
behavior; if restoration fails, include explicit recovery guidance in the
returned error message while retaining the existing stale-backup cleanup.
- Around line 27-34: Update the Cargo branch in InstallMethod::upgrade_hint to
return the command “cargo install --locked --force numan-cli”, preserving the
existing hints for all other installation methods.
In `@src/cmd/update.rs`:
- Around line 88-95: Add a unit test for the self-update validation in
execute_with_hooks that constructs UpdateArgs with self_update: true and
package: Some(...), then asserts the returned error matches "--self cannot be
combined with a package name". Keep the existing early return before
warn_stale_lifecycle_journal and state-lock handling so self-update does not
emit stale-journal warnings or mutate managed state.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 57537df5-47ab-4ec0-a877-e5d10f0bf7d5
📒 Files selected for processing (6)
AGENTS.mdCHANGELOG.mdREADME.mdsrc/cmd/mod.rssrc/cmd/self_update.rssrc/cmd/update.rs
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
tonythethompson/QuickShell(manual)tonythethompson/numan(manual)tonythethompson/dependency-chain-substrate(manual)
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
- GitHub Check: Real-Nu acceptance (windows-latest)
- GitHub Check: Test (windows-latest)
- GitHub Check: Analyze (rust)
🧰 Additional context used
📓 Path-based instructions (11)
**/*
📄 CodeRabbit inference engine (CLAUDE.md)
**/*: Use Serena's semantic, symbol-aware tools as the primary tools for reading and editing code; use built-in Read, Glob, Grep, and Edit only under the stated exceptions.
Before editing a code file, inspect its symbol overview, read the specific symbols being changed, and edit them with Serena's symbol-aware tools.
Understand the existing code before changing it and make the smallest change that satisfies the request; avoid unrelated cleanup, premature abstractions, unnecessary error handling, feature flags, and compatibility shims.
Prefer editing existing files over creating new ones, and never create Markdown or README files unless explicitly requested.
For exploratory questions, provide a 2–3 sentence recommendation with the main tradeoff and do not implement until the user agrees.
For UI or frontend changes that cannot be tested in a browser, explicitly state that browser testing was not performed rather than claiming success.
Address security issues when discovered, including injection, XSS, SQL injection, path traversal, and secret leaks.
Pause and obtain confirmation before destructive, hard-to-reverse, externally visible, or third-party-upload actions, including deleting files or branches, dropping tables, force-pushing, modifying CI/CD, posting externally, or uploading content.
When blocked, investigate the root cause instead of bypassing it with --no-verify, --force, or deletion; investigate unfamiliar files, branches, and configuration before deleting them.
Only commit when explicitly asked; do not proactively update git configuration or push changes.
Do not skip Git hooks unless explicitly asked; if a pre-commit hook fails, fix the issue, re-stage, and create a new commit rather than amending.
Stage files by name rather than using git add -A or git add ., to avoid accidentally including secrets or large binaries.
Use a HEREDOC for commit messages, and add co-author attribution only when the user explicitly requests the exact trailer.
Do not force-pus...
Files:
src/cmd/update.rssrc/cmd/mod.rsCHANGELOG.mdREADME.mdAGENTS.mdsrc/cmd/self_update.rs
**/*.{js,jsx,ts,tsx,py,java,go,rs,rb,php,c,cpp,h,hpp,cs,swift,kt,kts}
📄 CodeRabbit inference engine (CLAUDE.md)
Add comments only when the WHY is non-obvious; do not narrate what the code does, reference the current task, or reference the PR in comments.
Files:
src/cmd/update.rssrc/cmd/mod.rssrc/cmd/self_update.rs
!**/.env,!**/credentials.json,!**/*.pem
📄 CodeRabbit inference engine (CLAUDE.md)
Do not commit files that appear to contain secrets, including .env, credentials.json, and PEM files; warn before doing so even if explicitly requested.
Files:
src/cmd/update.rssrc/cmd/mod.rsCHANGELOG.mdREADME.mdAGENTS.mdsrc/cmd/self_update.rs
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs: Use the Rust 2021 edition.
Useanyhow::Resultwith.context(...)in application code; usethiserrorfor library error types that callers match on.
Useclapderive macros for CLI definitions.
Useserdewithserde_jsonortomlfor serialization.
Function parameters must use&Path, not&PathBuf.
Library code must not panic; error paths should returnanyhow::Resultwith context where appropriate.
Add or update tests for behavior changes, including relevant failure paths.
New mutating code paths must acquire the mutation lock viaacquire_mutation_lock(root)and snapshot the lockfile before writes.
Lockfile, journal, and state-file JSON writes must usewrite_json_atomic.
numan installmust write only to$NUMAN_ROOT; it must not invoke Nu or register plugins/autoloads.
Onlyactivateanddeactivatemay modify Nu integration state.
Treat the lockfile as the authoritative source of truth; derived projections such as autoload state must not be authoritative.
Install payloads under versioned, content-addressed paths and never overwrite them in place.
Never overwrite foreign autoload files; respectOWNERSHIP_MARKER.
Pass plugin paths through environment variables only; do not use runtime interpolation in Nu program strings.
**/*.rs: All CI gates must pass:cargo test,cargo clippy -- -D warnings, andcargo fmt --check.
Every mutating command—includinginstall,remove,update,gc, and futurenupm import—must callacquire_mutation_lock(root).
Lockfiles, journals, and state files must usewrite_json_atomic; partial writes are not allowed.
Pending activation, autoload, and lifecycle journals must be stored under$NUMAN_ROOT/state/.
Module autoload identity must match all four fields: Nu executable hash, Nu version, vendor autoload directory, and managed file path; the lockfilemodule_activationvalue is authoritative.
Never overwrite foreign autoload files; respectOWNERSHIP_MARKER.
Pass paths to Nu only throu...
Files:
src/cmd/update.rssrc/cmd/mod.rssrc/cmd/self_update.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Run and keep
cargo fmt/rustfmtclean, and ensurecargo clippy -- -D warningspasses.
Files:
src/cmd/update.rssrc/cmd/mod.rssrc/cmd/self_update.rs
**/*.{rs,nu}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.{rs,nu}: Real-Nu acceptance tests must be marked#[ignore]and should be run when changes affect activation or nupm import; unit tests must not spawn realnuand should use injectable seams such asFakeCandidateRunneror registrars.
The nupm integration must be read-only towardNUPM_HOME, must not executebuild.nu, and must not perform bidirectional synchronization.Unit tests must use
FakeCandidateRunneror injectable registrars and must not spawn a realnuprocess.
Files:
src/cmd/update.rssrc/cmd/mod.rssrc/cmd/self_update.rs
**/*.{rs,md}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Match existing naming, module layout, and documentation level in the file being edited; update
AGENTS.md,docs/, or command help when structure, conventions, or user-visible behavior changes.Tests must cover failure modes, not only successful execution.
Files:
src/cmd/update.rssrc/cmd/mod.rsCHANGELOG.mdREADME.mdAGENTS.mdsrc/cmd/self_update.rs
**/*.{rs,md,toml}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Use the repository's established serialization and module conventions rather than introducing unrelated refactors.
Files:
src/cmd/update.rssrc/cmd/mod.rsCHANGELOG.mdREADME.mdAGENTS.mdsrc/cmd/self_update.rs
src/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
Include failure context with
.context("what failed")or equivalentanyhowcontext when propagating application errors.
Files:
src/cmd/update.rssrc/cmd/mod.rssrc/cmd/self_update.rs
src/cmd/update.rs
📄 CodeRabbit inference engine (AGENTS.md)
Active-plugin update orchestration must be disabled by default and enabled only when
NUMAN_ENABLE_ACTIVE_PLUGIN_MUTATIONequals exactly1; the flow is deactivate → upgrade → activate.
Files:
src/cmd/update.rs
**/*.md
📄 CodeRabbit inference engine (REVIEW.md)
Update documentation and
AGENTS.mdwhen project structure or conventions change.
Files:
CHANGELOG.mdREADME.mdAGENTS.md
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: tonythethompson/numan
Timestamp: 2026-08-06T02:18:09.860Z
Learning: Run CI-equivalent validation: `cargo test`, `cargo clippy -- -D warnings`, and `cargo fmt --check`; ignored acceptance tests require Nu 0.113 on PATH.
Learnt from: CR
Repo: tonythethompson/numan
Timestamp: 2026-08-06T02:18:09.860Z
Learning: Do not force-push to `master`; use imperative commit messages under 72 characters and feature/fix branch naming.
🔍 Remote MCP GitHub Copilot
Review-relevant context
- PR
#94is a draft with one commit. Format, clippy, Linux/macOS tests, MSRV, and packaging checks passed; Windows/macOS acceptance and Rust CodeQL were still running, while CodeRabbit status remained pending. - The release workflow publishes exactly three supported targets: Linux GNU x86_64, Windows MSVC x86_64, and macOS ARM64. It packages the binary one directory deep and generates
SHA256SUMSfrom allnuman-*archives. - The current
v0.2.0release contains the three expected archive names plusSHA256SUMS, matching the new asset-selection logic. Platform::detect()also recognizes Linux musl and macOS Intel, but the PR intentionally rejects those targets because no corresponding release assets are built.--selfrejects a package argument and bypasses package-state warnings and the mutation lock; this is intentional because it replaces the CLI executable rather than package data.- The PR’s remaining validation explicitly includes manual published-release
--checktesting and package-manager detection checks. The added tests cover helper logic and check-mode download avoidance, but not an end-to-end archive extraction or binary replacement. - Related PR
#93is closed and unmerged, so this PR’s install-method detection is independent of the proposed cross-channel install-guard implementation.
🔇 Additional comments (13)
AGENTS.md (1)
61-62: LGTM!CHANGELOG.md (1)
10-13: LGTM!README.md (1)
353-353: LGTM!Also applies to: 383-383
src/cmd/mod.rs (1)
16-16: LGTM!src/cmd/update.rs (1)
33-37: LGTM!src/cmd/self_update.rs (8)
13-15: LGTM!
85-108: LGTM!
174-199: LGTM!
266-295: LGTM!
301-347: LGTM!
429-564: LGTM!
111-141: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low valueSecurity Misconfiguration (CWE-347)
Reachability: External
Reachability path
● Entry src/cmd/mod.rs │ ▼ ● Hop src/cmd/update.rs:70 execute │ ▼ ● Sink src/cmd/self_update.rsParser is solid; be honest about what the checksum actually proves.
The parsing is correct for GNU, BSD-star, and tab-separated forms, and the 64-hex-digit guard rejects junk lines cleanly.
One readiness-honesty point.
SHA256SUMSand the archive come from the same origin with the same trust anchor, andSHA256SUMSis not signed. So this verification protects against a truncated or corrupted download. It does not protect against a compromised release. The PR description says the asset is "verified", which reads stronger than what the mechanism delivers. Either state the limitation in the README self-update section, or add minisign/cosign signature verification overSHA256SUMSin a follow-up.Minor parser note in the same area:
map.insertlets a later line silently override an earlier entry for the same basename after the path component is stripped. That grants no extra capability to an attacker who already controls the release, but rejecting duplicate keys would make the parser stricter for free.
201-203: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winSensitive Data Exposure (CWE-319): Cleartext Transmission of Sensitive Information
Reachability: External
Reachability path
● Entry src/cmd/mod.rs │ ▼ ● Hop src/cmd/update.rs:70 execute │ ▼ ● Sink src/cmd/self_update.rsVerify that
download_filepins HTTPS across the redirect chain.Both the archive and
SHA256SUMSare fetched throughdownload_fileusing URLs taken from the release JSON.src/install/download.rsis not in this diff, so its scheme enforcement, redirect policy, and timeout are unproven here.This matters more than a normal download. An on-path attacker who can serve one plaintext hop can serve both the archive and
SHA256SUMS, and the digest comparison then compares attacker bytes against an attacker hash. Verifying the archive only helps if the transport for both fetches is authenticated and encrypted. GitHub asset URLs redirect toobjects.githubusercontent.com, so redirects must be followed. The scheme must stayhttpson every hop.If
download_filedoes not already enforce this, reject any non-httpsasset_urlandsums_urlinexecute_with_clientbefore the fetch.#!/bin/bash # Description: Inspect download_file transport properties: scheme checks, redirect policy, timeouts. set -euo pipefail fd -t f 'download.rs' src | while IFS= read -r f; do echo "===== $f =====" cat -n "$f" done echo "===== redirect / scheme / timeout usage across the crate =====" rg -nP --type=rust -C3 'redirect\s*\(|Policy::|\.timeout\s*\(|starts_with\("https|scheme\(\)'
There was a problem hiding this comment.
Sorry @tonythethompson, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
PR Summary by QodoAdd
AI Description
Diagram
High-Level Assessment
Files changed (6)
|
Greptile SummaryAdds self-updates for standalone installations while directing package-manager installations to their native upgrade commands.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains; the staged Unix replacement resolves the destructive permission-failure path, and signed checksums establish independent authenticity before installation.
|
| Filename | Overview |
|---|---|
| src/cmd/self_update.rs | Implements install-method detection, release discovery, signed-checksum verification, archive extraction, and platform-specific staged binary replacement; both previously reported defects are addressed. |
| .github/workflows/release.yml | Generates and signs SHA256SUMS before uploading all distribution artifacts to the GitHub release. |
| scripts/sign-sha256sums.py | Produces the detached base64 Ed25519 signature format consumed by the Rust verifier. |
| src/cmd/update.rs | Integrates the self-update mode into the existing update command without altering package-update behavior. |
| src/install/download.rs | Strengthens download transport handling by rejecting HTTPS-to-HTTP redirects. |
Reviews (6): Last reviewed commit: "Add path context to streaming SHA-256 fi..." | Re-trigger Greptile
Inject exe into the self-update test seam, preserve Unix modes, stage Windows replacements before rename, defer asset naming until apply, require https URLs, tighten the cargo upgrade hint, clarify README managed-install behavior, and expand failure-path tests. Co-authored-by: Anthony Thompson <github@trackdub.com>
Code Review by Qodo
1.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6bf16dacf3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Stage permissions on the temp binary before persist so a mode failure cannot leave dest non-executable. Restore CodeRabbit self-update hardening that was clobbered by an autofix pass, keep streaming checksums and HTTPS redirect refusal from download/integrity. Co-authored-by: Anthony Thompson <github@trackdub.com>
Co-authored-by: Anthony Thompson <github@trackdub.com>
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/cmd/self_update.rs (1)
207-228: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winCheck managed installs before printing the upgrade hint.
When
checkis true, this return path executes beforefetch_latest. The command then prints an upgrade command even when the installed version is current. Fetch and compare release metadata in check mode before reporting availability.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cmd/self_update.rs` around lines 207 - 228, Update execute_with_client so check mode fetches and compares release metadata before the method.upgrade_hint() early return. Only print the managed-install upgrade hint when not checking, or after confirming an update is available; preserve the existing hint behavior for normal execution.Source: MCP tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/cmd/self_update.rs`:
- Around line 207-219: Update execute_with_client and its caller execute to
resolve the installation root and lock state, then call
acquire_mutation_lock(root) and snapshot the lockfile before any self-update
write or replace_binary operation. Thread the required root and lock-state
values through the self-update flow while preserving the existing release-client
and version injection behavior.
In `@src/core/integrity.rs`:
- Around line 6-18: Update hash_file to attach anyhow context to both File::open
and reader.read failures, including the operation and affected path in each
message. Preserve the existing hashing behavior and Result-based error
propagation.
---
Outside diff comments:
In `@src/cmd/self_update.rs`:
- Around line 207-228: Update execute_with_client so check mode fetches and
compares release metadata before the method.upgrade_hint() early return. Only
print the managed-install upgrade hint when not checking, or after confirming an
update is available; preserve the existing hint behavior for normal execution.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 2985220b-ead0-487e-ad64-cbe7d59e874e
📒 Files selected for processing (3)
src/cmd/self_update.rssrc/core/integrity.rssrc/install/download.rs
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
tonythethompson/QuickShell(manual)tonythethompson/numan(manual)tonythethompson/dependency-chain-substrate(manual)
📜 Review details
⏰ Context from checks skipped due to timeout. (4)
- GitHub Check: Greptile Review
- GitHub Check: Test (windows-latest)
- GitHub Check: Real-Nu acceptance (windows-latest)
- GitHub Check: Analyze (rust)
🧰 Additional context used
📓 Path-based instructions (11)
**/*
📄 CodeRabbit inference engine (CLAUDE.md)
**/*: Use Serena's semantic, symbol-aware tools as the primary tools for reading and editing code; use built-in Read, Glob, Grep, and Edit only under the stated exceptions.
Before editing a code file, inspect its symbol overview, read the specific symbols being changed, and edit them with Serena's symbol-aware tools.
Understand the existing code before changing it and make the smallest change that satisfies the request; avoid unrelated cleanup, premature abstractions, unnecessary error handling, feature flags, and compatibility shims.
Prefer editing existing files over creating new ones, and never create Markdown or README files unless explicitly requested.
For exploratory questions, provide a 2–3 sentence recommendation with the main tradeoff and do not implement until the user agrees.
For UI or frontend changes that cannot be tested in a browser, explicitly state that browser testing was not performed rather than claiming success.
Address security issues when discovered, including injection, XSS, SQL injection, path traversal, and secret leaks.
Pause and obtain confirmation before destructive, hard-to-reverse, externally visible, or third-party-upload actions, including deleting files or branches, dropping tables, force-pushing, modifying CI/CD, posting externally, or uploading content.
When blocked, investigate the root cause instead of bypassing it with --no-verify, --force, or deletion; investigate unfamiliar files, branches, and configuration before deleting them.
Only commit when explicitly asked; do not proactively update git configuration or push changes.
Do not skip Git hooks unless explicitly asked; if a pre-commit hook fails, fix the issue, re-stage, and create a new commit rather than amending.
Stage files by name rather than using git add -A or git add ., to avoid accidentally including secrets or large binaries.
Use a HEREDOC for commit messages, and add co-author attribution only when the user explicitly requests the exact trailer.
Do not force-pus...
Files:
src/install/download.rssrc/core/integrity.rssrc/cmd/self_update.rs
**/*.{js,jsx,ts,tsx,py,java,go,rs,rb,php,c,cpp,h,hpp,cs,swift,kt,kts}
📄 CodeRabbit inference engine (CLAUDE.md)
Add comments only when the WHY is non-obvious; do not narrate what the code does, reference the current task, or reference the PR in comments.
Files:
src/install/download.rssrc/core/integrity.rssrc/cmd/self_update.rs
!**/.env,!**/credentials.json,!**/*.pem
📄 CodeRabbit inference engine (CLAUDE.md)
Do not commit files that appear to contain secrets, including .env, credentials.json, and PEM files; warn before doing so even if explicitly requested.
Files:
src/install/download.rssrc/core/integrity.rssrc/cmd/self_update.rs
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs: Use the Rust 2021 edition.
Useanyhow::Resultwith.context(...)in application code; usethiserrorfor library error types that callers match on.
Useclapderive macros for CLI definitions.
Useserdewithserde_jsonortomlfor serialization.
Function parameters must use&Path, not&PathBuf.
Library code must not panic; error paths should returnanyhow::Resultwith context where appropriate.
Add or update tests for behavior changes, including relevant failure paths.
New mutating code paths must acquire the mutation lock viaacquire_mutation_lock(root)and snapshot the lockfile before writes.
Lockfile, journal, and state-file JSON writes must usewrite_json_atomic.
numan installmust write only to$NUMAN_ROOT; it must not invoke Nu or register plugins/autoloads.
Onlyactivateanddeactivatemay modify Nu integration state.
Treat the lockfile as the authoritative source of truth; derived projections such as autoload state must not be authoritative.
Install payloads under versioned, content-addressed paths and never overwrite them in place.
Never overwrite foreign autoload files; respectOWNERSHIP_MARKER.
Pass plugin paths through environment variables only; do not use runtime interpolation in Nu program strings.
**/*.rs: All CI gates must pass:cargo test,cargo clippy -- -D warnings, andcargo fmt --check.
Every mutating command—includinginstall,remove,update,gc, and futurenupm import—must callacquire_mutation_lock(root).
Lockfiles, journals, and state files must usewrite_json_atomic; partial writes are not allowed.
Pending activation, autoload, and lifecycle journals must be stored under$NUMAN_ROOT/state/.
Module autoload identity must match all four fields: Nu executable hash, Nu version, vendor autoload directory, and managed file path; the lockfilemodule_activationvalue is authoritative.
Never overwrite foreign autoload files; respectOWNERSHIP_MARKER.
Pass paths to Nu only throu...
Files:
src/install/download.rssrc/core/integrity.rssrc/cmd/self_update.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Run and keep
cargo fmt/rustfmtclean, and ensurecargo clippy -- -D warningspasses.
Files:
src/install/download.rssrc/core/integrity.rssrc/cmd/self_update.rs
**/*.{rs,nu}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.{rs,nu}: Real-Nu acceptance tests must be marked#[ignore]and should be run when changes affect activation or nupm import; unit tests must not spawn realnuand should use injectable seams such asFakeCandidateRunneror registrars.
The nupm integration must be read-only towardNUPM_HOME, must not executebuild.nu, and must not perform bidirectional synchronization.Unit tests must use
FakeCandidateRunneror injectable registrars and must not spawn a realnuprocess.
Files:
src/install/download.rssrc/core/integrity.rssrc/cmd/self_update.rs
**/*.{rs,md}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Match existing naming, module layout, and documentation level in the file being edited; update
AGENTS.md,docs/, or command help when structure, conventions, or user-visible behavior changes.Tests must cover failure modes, not only successful execution.
Files:
src/install/download.rssrc/core/integrity.rssrc/cmd/self_update.rs
**/*.{rs,md,toml}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Use the repository's established serialization and module conventions rather than introducing unrelated refactors.
Files:
src/install/download.rssrc/core/integrity.rssrc/cmd/self_update.rs
src/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.rs: Use compile-time#[cfg(target_env)]platform detection rather thanstd::env::consts;LIBCis a compile-time constant.
Useclapderive macros for the CLI implementation.
Files:
src/install/download.rssrc/core/integrity.rssrc/cmd/self_update.rs
src/install/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
Install operations must remain inert: they may write only to
$NUMAN_ROOTand must not perform Nu integration.
Files:
src/install/download.rs
src/core/integrity.rs
📄 CodeRabbit inference engine (AGENTS.md)
Compute and verify artifact SHA256 hashes.
Files:
src/core/integrity.rs
🔍 Remote MCP GitHub Copilot
Additional review context
- PR
#94has one unresolved P1 concern: managed-install--self --checkreturns the package-manager hint before fetching release metadata, so it does not determine whether an update is available. - One unresolved security concern remains: SHA-256 verification is not independently authenticating because both the archive and
SHA256SUMSoriginate from the same GitHub Release. - The release workflow publishes the three supported platform archives and generates
SHA256SUMSfrom those artifacts. - Earlier review findings about HTTPS enforcement, streaming checksum hashing, Windows staging, Unix permissions, and test coverage were marked resolved in PR comments.
- PR
#93’s channel detection is related but remains unmerged, so self-update’s independent detection behavior should not assume those safeguards are available.
🔀 Multi-repo context tonythethompson/QuickShell, tonythethompson/dependency-chain-substrate
Linked repositories findings
tonythethompson/QuickShell
- GitHub release artifacts are Windows installer executables (
QuickShell-Setup-*-x64.exe/*-arm64.exe), while WinGet uses separate package identifiers. This supports treating package-managed installs differently from standalone binary updates. [::tonythethompson/QuickShell::].github/workflows/release-extension.yml:203-221,docs/release-packages.md:35-59 - WinGet updates are submitted externally with
wingetcreate; no application-level self-replacement contract is present. [::tonythethompson/QuickShell::].github/workflows/release-extension.yml:244-368
tonythethompson/dependency-chain-substrate
- Releases publish
.nupkgpackages and usedotnet tool install/update, not standalone binaries orSHA256SUMS. [::tonythethompson/dependency-chain-substrate::].github/workflows/release.yml:80-143,scripts/install-dcs-from-release.ps1:1-42 - Release tags follow
v<semver>and are validated against the project version, but this repository provides no reusable standalone-update artifact contract. [::tonythethompson/dependency-chain-substrate::].github/workflows/release.yml:25-48
No linked repository contains consumers of numan or its new self_update APIs.
🔇 Additional comments (9)
src/cmd/self_update.rs (7)
31-31: Restore the forced Cargo upgrade command.
cargo install numan-clican leave an existing installation unchanged. Usecargo install --locked --force numan-cli.
243-243: Resolve the platform asset only after status checks.
release_asset_namecan reject an unsupported platform before the up-to-date and check-mode returns. Move it to the apply path so--self --checkcan still report the version status.
373-378: Preserve the existing Unix file mode.
make_executablechanges a restrictive mode such as0o700to0o755. Preserve the destination mode and add only the required owner-execute bit.
386-414: Stage the Windows replacement before moving the running binary.The code renames
destbefore it writes the replacement temp file. A process interruption during the write leaves nonuman.exe. Write and flush the staged file first, then rename the running binary and persist the staged file. Include manual recovery guidance if rollback fails.
433-572: LGTM!
574-598: LGTM!
274-280: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy liftOther (CWE-494): Download of Code Without Integrity Check
Reachability: External
Reachability path
● Entry src/cmd/self_update.rs:10 download_file │ ▼ ● Sink src/install/download.rsUse an independently authenticated release manifest.
The release metadata selects both the archive and
SHA256SUMS. HTTPS protects transport, but the checksum does not authenticate the archive when one release publisher can replace both files. An attacker with release-publishing access can supply a matching malicious binary that reachesreplace_binary. Verify a signed manifest or provenance attestation against a trust root that is independent of the fetched release assets.src/core/integrity.rs (1)
21-23: LGTM!Also applies to: 38-39
src/install/download.rs (1)
39-42: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winSecurity Misconfiguration (CWE-319): Cleartext Transmission of Sensitive Information
Reachability: External
Reachability path
● Entry src/cmd/self_update.rs:10 download_file │ ▼ ● Sink src/install/download.rsParse the source URL before enforcing the no-downgrade rule.
starts_with("https://")is case-sensitive. A case-variant HTTPS URL can pass the self-update preflight but skip this final redirect check. Parseurland compare its scheme instead of matching the raw string. Add a regression test that redirects a case-variant HTTPS source to HTTP.
Verify SHA256SUMS.sig with a baked-in release public key before trusting checksums. Sign releases via scripts/sign-sha256sums.py when NUMAN_RELEASE_SIGNING_KEY is set. Keep Unix staged permission apply. Co-authored-by: Anthony Thompson <github@trackdub.com>
Homebrew, winget, and cargo installs still cannot self-replace, but --check now fetches the latest release and reports whether an update is available before printing the package-manager upgrade hint. Co-authored-by: Anthony Thompson <github@trackdub.com>
Surface open/read failures with the affected path so integrity check errors are actionable during self-update and package verify. Co-authored-by: Anthony Thompson <github@trackdub.com>
Summary
Adds
numan update --selfso users can upgrade the numan CLI itself (not just registry packages).SHA256SUMSandSHA256SUMS.sig, verify the Ed25519 signature with a baked-in release public key, verify the archive digest, extract, and replace the running binary (Unix: stage bytes + mode on a temp file then persist; Windows: stage then rename-aside).update --selfprints the package-manager upgrade command.update --self --checkqueries GitHub Releases first and reports whether a newer version exists, then prints the upgrade hint only when an update is available.SHA256SUMSwhenNUMAN_RELEASE_SIGNING_KEYis set (scripts/sign-sha256sums.py).httpsURLs;download_filerefuses HTTPS→HTTP redirects.Review follow-ups
--checknow compares release versions before printing the upgrade hint.Maintainer note
Add repository secret
NUMAN_RELEASE_SIGNING_KEY(base64 32-byte Ed25519 seed matchingRELEASE_SUMS_PUBLIC_KEY_B64insrc/cmd/self_update.rs). Seedocs/RELEASING.md.Test plan
cargo test --lib self_update(35 tests)cargo clippy -- -D warningscargo fmt --checkNUMAN_RELEASE_SIGNING_KEYsecret before the next tagged releasenuman update --self --check/ apply--checkreports version status