Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ brews:
install: |
bin.install "aicr"
bin.install "aicr-attestation.sigstore.json" if File.exist? "aicr-attestation.sigstore.json"
generate_completions_from_executable(bin/"aicr", "completion")
test: |
assert_match version.to_s, shell_output("#{bin}/aicr version")
caveats: |
Expand Down
49 changes: 36 additions & 13 deletions docs/user/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ This script:
- Detects your OS and architecture automatically
- Downloads the appropriate binary from GitHub releases
- Installs to `/usr/local/bin/aicr` by default (use `-d <dir>` for a custom location)
- Installs shell completions for bash, zsh, and fish (set `AICR_NO_COMPLETIONS=1` to skip)
- Verifies the installation
- Uses `GITHUB_TOKEN` environment variable for authenticated API calls (avoids rate limits)

Expand Down Expand Up @@ -99,26 +100,41 @@ Expected output shows version information and available commands.

## Post-Installation

### Shell Completion (Optional)
### Shell Completion

Enable shell auto-completion for command and flag names:
Tab completion for commands and flags is installed automatically by both the Homebrew formula and the install script. No manual setup is required.

**Opt out** (install script only): set `AICR_NO_COMPLETIONS=1` before running the script:

**Bash:**
```shell
# Add to ~/.bashrc
source <(aicr completion bash)
AICR_NO_COMPLETIONS=1 curl -sfL https://raw.githubusercontent.com/NVIDIA/aicr/main/install | bash -s --
```

**Zsh:**
**Manual setup** (build from source or `go install`):

Bash:
```shell
# Add to ~/.zshrc
source <(aicr completion zsh)
aicr completion bash > "${BASH_COMPLETION_USER_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion}/completions/aicr"
```

Zsh:
```shell
aicr completion zsh > "${XDG_DATA_HOME:-$HOME/.local/share}/zsh/site-functions/_aicr"
```

**Fish:**
Fish:
```shell
# Add to ~/.config/fish/config.fish
aicr completion fish | source
aicr completion fish > ~/.config/fish/completions/aicr.fish
```

Alternatively, source completions dynamically in your shell RC file (evaluates on every shell start):

```shell
# Bash (~/.bashrc)
source <(aicr completion bash)

# Zsh (~/.zshrc)
source <(aicr completion zsh)
```

## Container Images
Expand Down Expand Up @@ -180,8 +196,15 @@ nvidia-smi
# Remove binary
sudo rm /usr/local/bin/aicr

# Remove shell completion (if configured)
# Remove the source line from your shell RC file
# Remove shell completions (remove whichever exist)
sudo rm -f /usr/share/bash-completion/completions/aicr
sudo rm -f /usr/local/share/zsh/site-functions/_aicr
sudo rm -f /opt/homebrew/share/zsh/site-functions/_aicr
sudo rm -f /opt/homebrew/etc/bash_completion.d/aicr
sudo rm -f /usr/local/etc/bash_completion.d/aicr
rm -f "${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion/completions/aicr"
rm -f "${XDG_DATA_HOME:-$HOME/.local/share}/zsh/site-functions/_aicr"
rm -f "${XDG_CONFIG_HOME:-$HOME/.config}/fish/completions/aicr.fish"
```

## Getting Help
Expand Down
96 changes: 95 additions & 1 deletion install
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ Install utility for $BIN_NAME
Usage: $0 [-d install_dir]

Environment Variables:
GITHUB_TOKEN GitHub token to avoid API rate limits (no special scopes required)
GITHUB_TOKEN GitHub token to avoid API rate limits (no special scopes required)
AICR_NO_COMPLETIONS Set to 1 to skip shell completion installation

Examples:
$0 # Install to /usr/local/bin
Expand Down Expand Up @@ -106,6 +107,96 @@ get_archive_name() {
echo "${BIN_NAME}_${ver}_${2}_${3}.tar.gz" # version, os, arch
}

# ==============================================================================
# Shell Completion Setup
# ==============================================================================

write_completion() {
local bin_path="$1" shell="$2" target="$3"
local target_dir tmp_file
target_dir=$(dirname "$target")
mkdir -p "$target_dir" 2>/dev/null || sudo mkdir -p "$target_dir" 2>/dev/null || return 1
tmp_file=$(mktemp) || return 1
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[Major — confirmed by all 3 reviewers] mktemp creates files with 0600 permissions. After sudo mv to a system completion dir, non-root users can't read the file — completions silently fail. Add chmod 644 "$tmp_file" before the mv.

Iterative cross-review: Claude Code AGREE, Codex AGREE, CodeRabbit AGREE

if ! "$bin_path" completion "$shell" > "$tmp_file" 2>/dev/null || [[ ! -s "$tmp_file" ]]; then
rm -f "$tmp_file"
return 1
fi
if [[ -w "$target_dir" ]]; then
mv "$tmp_file" "$target" || { rm -f "$tmp_file"; return 1; }
else
sudo mv "$tmp_file" "$target" || { rm -f "$tmp_file"; return 1; }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is the main thing — mktemp creates files 0600, so after sudo mv nobody else can read them and completions silently break. Slap a chmod 644 "$tmp_file" before the sudo mv branch and you're good.

fi
}

setup_bash_completions() {
local bin_path="$1" os="$2" xdg_data="$3"
local sys_dir
if [[ "$os" == "darwin" ]]; then
local brew_prefix="/usr/local"
[[ -d /opt/homebrew ]] && brew_prefix="/opt/homebrew"
sys_dir="${brew_prefix}/etc/bash_completion.d"
else
sys_dir="/usr/share/bash-completion/completions"
fi

if write_completion "$bin_path" bash "${sys_dir}/aicr"; then
ok "Bash completions installed"
elif write_completion "$bin_path" bash "${xdg_data}/bash-completion/completions/aicr"; then
ok "Bash completions installed (user-local)"
else
warn "Could not install bash completions"
fi
}

setup_zsh_completions() {
local bin_path="$1" os="$2" xdg_data="$3"
local sys_dir
if [[ "$os" == "darwin" ]]; then
local brew_prefix="/usr/local"
[[ -d /opt/homebrew ]] && brew_prefix="/opt/homebrew"
sys_dir="${brew_prefix}/share/zsh/site-functions"
else
sys_dir="/usr/local/share/zsh/site-functions"
fi

if write_completion "$bin_path" zsh "${sys_dir}/_aicr"; then
ok "Zsh completions installed"
elif write_completion "$bin_path" zsh "${xdg_data}/zsh/site-functions/_aicr"; then
ok "Zsh completions installed (user-local)"
else
warn "Could not install zsh completions"
fi
}

setup_fish_completions() {
local bin_path="$1"
local fish_dir="${XDG_CONFIG_HOME:-$HOME/.config}/fish"
[[ -d "$fish_dir" ]] || return 0
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[Minor — confirmed by all 3 reviewers] Fish completions only install to user dir. Under sudo, $HOME resolves to /root, so completions land in /root/.config/fish/ — useless for the actual user. Bash/zsh try system dirs first with a user-dir fallback, but fish has no system-dir attempt. Consider adding a system path fallback (e.g., /usr/share/fish/vendor_completions.d/).

Iterative cross-review: Claude Code AGREE (Low), Codex AGREE (Medium), CodeRabbit AGREE

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

When the script runs under sudo, $HOME is /root so fish completions end up in /root/.config/fish/ — not super useful. Bash/zsh handle this by trying system dirs first. Maybe try /usr/share/fish/vendor_completions.d/ before falling back to the user dir?


if write_completion "$bin_path" fish "${fish_dir}/completions/aicr.fish"; then
ok "Fish completions installed"
else
warn "Could not install fish completions"
fi
}

setup_completions() {
if [[ "${AICR_NO_COMPLETIONS:-0}" == "1" ]]; then
info "Skipping shell completion setup (AICR_NO_COMPLETIONS=1)"
return 0
fi

local bin_path="${INSTALL_DIR}/${BIN_NAME}"
local os xdg_data
os=$(get_os)
xdg_data="${XDG_DATA_HOME:-$HOME/.local/share}"
step "Setting up shell completions..."

setup_bash_completions "$bin_path" "$os" "$xdg_data"
setup_zsh_completions "$bin_path" "$os" "$xdg_data"
setup_fish_completions "$bin_path"
}

# ==============================================================================
# GitHub API Functions
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[Minor — confirmed by all 3 reviewers] || true swallows all errors from setup_completions, including catastrophic failures like get_os failing. The individual sub-functions already warn, but a top-level catch would help edge cases. Consider: setup_completions || warn "Shell completion setup failed (non-fatal)"

Iterative cross-review: Claude Code AGREE, Codex AGREE, CodeRabbit AGREE

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: || true eats everything silently. Maybe || warn "Shell completion setup failed (non-fatal)" so there's at least a breadcrumb if something weird happens?

# ==============================================================================
Expand Down Expand Up @@ -313,6 +404,9 @@ main() {
[[ -f "${INSTALL_DIR}/${BIN_NAME}-attestation.sigstore.json" ]] && \
msg "Attestation: ${INSTALL_DIR}/${BIN_NAME}-attestation.sigstore.json"

# Install shell completions
setup_completions || true

# Fetch latest Sigstore trusted root for offline verification.
# The trusted root enables 'aicr verify' to check attestation signatures
# without contacting Sigstore infrastructure. If this fails (e.g., no network),
Expand Down
Loading