feat(duo): add cli command with binary download management
Summary
Implements glab duo cli command that automatically downloads, manages, and executes the GitLab Duo CLI binary from the GitLab Package Registry. This provides a seamless installation experience similar to npx, but with glab managing the binary lifecycle.
Command naming: The command is glab duo cli (with glab duo aliased to it for convenience). This preserves agent for potential future use and aligns the command name with the underlying "GitLab Duo CLI" tool.
Recent Updates
Command Rename (Latest)
- Renamed command from
agenttoclito better reflect the underlying "GitLab Duo CLI" tool - Updated all config keys:
duo_agent_*→duo_cli_* - Updated command structure to follow MR review guidelines (
.gitlab/duo/mr-review-instructions.yaml) - Added
complete()method for proper command pattern compliance - Command is now
glab duo cli(withglab duoaliased to it)
API Integration Improvements
- Refactored to use proper
client-goAPI methods throughout-
client.Packages.ListProjectPackages()for package listing -
client.Packages.ListPackageFiles()for file metadata -
client.GenericPackages.DownloadPackageFile()for downloads
-
- Improved type safety (fixed int vs int64 type mismatch)
- Removed manual URL construction and HTTP handling
Installation Directory Simplification
- Simplified to use platform standards directly:
- Unix:
~/.local/bin(systemd file-hierarchy specification standard) - Windows:
%LOCALAPPDATA%\Programs\Duo
- Unix:
- Removed unnecessary XDG checks (no XDG standard exists for executables)
- Clearer documentation about standard installation paths
Configuration Behavior Fixes
- Fixed
duo_cli_auto_download: falsebehavior to prompt instead of error - Fixed
duo_cli_auto_run: falsebehavior to prompt instead of error - Consistent semantic across all auto_* configs:
-
"true"→ auto-execute without prompting -
"false"or unset → prompt the user each time -
"false"means "don't auto-X", not "never X"
-
What This Does
For Users
- Running
glab duoorglab duo cliautomatically downloads and launches the Duo CLI - No need to manually install or manage the Duo CLI binary
- Automatic update checking with notifications
- Uses glab's authentication (OAuth2 tokens with auto-refresh via credential helper)
- Works across platforms: macOS (x64, arm64), Linux (x64, arm64), Windows (x64-baseline)
Key Features
Binary Management
- Downloads platform-specific binaries from GitLab Package Registry (project 46519181)
- Installs to standard locations:
- Unix:
~/.local/bin/duo - Windows:
%LOCALAPPDATA%\Programs\Duo\duo.exe
- Unix:
- SHA256 checksum verification for integrity
- Version tracking in glab config to prevent unnecessary re-downloads
- Manual updates via
glab duo cli --updateorglab duo --update
User Experience
- Interactive prompts for first-time download and execution
- Preferences saved to config (can be set to always prompt via
falsevalue) - Command alias:
glab duodefaults toglab duo cli - Unknown flags passed through to Duo CLI (via
FParseErrWhitelist.UnknownFlags) - Update checks every 24 hours (non-blocking, user notification only)
Authentication
- Uses
glab auth credential-helperfor token management - Duo CLI automatically calls credential helper (no manual token passing)
- Supports OAuth2 tokens with automatic refresh
- Centralized authentication through glab
Configuration
New config keys added to config.yaml:
duo_cli_auto_run: true/false # "true" = skip prompt, "false" = always prompt
duo_cli_auto_download: true/false # "true" = skip prompt, "false" = always prompt
duo_cli_binary_path: <path> # Installed binary location (auto-set)
duo_cli_binary_version: <version> # Installed version (auto-set)
duo_cli_binary_checksum: <sha256> # Binary checksum (auto-set)
duo_cli_last_update_check: <timestamp> # Last update check (auto-set)
Implementation Details
Architecture
-
internal/commands/duo/cli/: Main command package -
internal/commands/duo/cli/cliutils/: Utility package following glab's<command>utilspattern-
binaryManager: Handles download, installation, verification, and updates -
platform: Detects OS/arch and provides platform-specific paths and binary names
-
- GitLab Package Registry API integration using
client-golibrary - Atomic installation using temp files to prevent partial installs
- Follows complete/validate/run command pattern per MR review guidelines
API Integration
- Uses
gitlab.com/gitlab-org/api/client-gofor all GitLab API calls - Proper API methods with context support and type safety
- Unauthenticated client for public package downloads
- Structured error handling with clear user messages
Update Checking
- Background check every 24 hours (configurable via
GLAB_DUO_CLI_CHECK_UPDATE) - Uses
hashicorp/go-versionfor semantic version comparison - Non-blocking: shows notification only, doesn't interrupt user flow
- Version validation ensures glab-managed binaries (checks config metadata)
Error Handling
- Graceful network error handling with clear messages
- Mandatory checksum verification prevents corrupted installs
- Platform validation with helpful error messages
- Distinguishes between glab-managed and external binaries
Binary Execution
- Unix (macOS/Linux): Uses
syscall.Exec()to replace glab process with Duo CLI- Provides better signal handling and terminal control for interactive TUI
- Process replacement ensures clean terminal state
- Windows: Uses subprocess with exit code propagation
- Windows doesn't have exec(), so subprocess is required
- Exits with Duo CLI's exit code for proper error handling
Testing
- Command structure and flag handling
- Binary validation and checksum verification
- Platform detection for all supported combinations
- Config persistence and retrieval
- Update checking logic and version comparison
- Tests use
t.Parallel()where compatible (excluded for tests usingt.Setenv()) - All tests follow MR review guidelines (use
cmdtest, testify assertions)
Breaking Changes
None - this is a new command. The existing glab duo ask command is unchanged.
Known Limitations
Duo CLI Help Flag
- Duo CLI has a limitation where
--helpis intercepted by Bun runtime (shows Bun help instead of Duo CLI help) - This affects flag discoverability - tracking with Duo CLI team to address upstream
- Unknown flags are passed through successfully, but users must discover them via docs or source code
Duo Direct Command
-
glab duo directcurrently errors with a duo binary bug (not a glab issue) - Error:
TypeError: id is not an Object. (evaluating '"baseId" in id') - Arguments are correctly passed through by glab
- This is a bug in the upstream duo binary, not in our integration
- Non-blocking issue per reviewer feedback
Related
- Closes https://gitlab.com/gitlab-org/cli/-/issues/1978
- Replaces previous npx-based approach (MR !2564 (closed), never merged)
- Integrates with existing
glab auth credential-helper(merged separately) - Follows patterns from
release/downloadandsecurefile/downloadcommands
Testing Instructions
# Clean install test
rm -f ~/.local/bin/duo
glab config set duo_cli_auto_download false
glab duo
# → Should prompt to download (even with false value)
# → Should install binary
# → Should launch Duo CLI
# Update test
glab duo --update
# → Should check for latest version
# → Should show update status
# Config persistence test
glab config get duo_cli_binary_version
glab config get duo_cli_binary_path
# → Should show installed version and path
# Authentication test (requires OAuth2 login)
glab auth status
# → Ensure authenticated
glab duo
# → Should authenticate successfully via credential helper
# Test auto config behavior
glab config set duo_cli_auto_run false
glab duo
# → Should still prompt (not error)
# Test explicit cli subcommand
glab duo cli
# → Should work identically to `glab duo`
Edited by Kai Armstrong