Skip to content

Commit 1e6e430

Browse files
millsksCopilotruben-arts
authored
feat(install): Improve authentication handling and credential masking (#4948)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: Ruben Arts <[email protected]>
1 parent 0d8b2c2 commit 1e6e430

File tree

3 files changed

+91
-8
lines changed

3 files changed

+91
-8
lines changed

docs/installation.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ its [compile steps](https://github.com/conda/rattler/tree/main#give-it-a-try).
128128
| `PIXI_ARCH` | The architecture the Pixi version was built for. | `uname -m` |
129129
| `PIXI_NO_PATH_UPDATE`| If set the `$PATH` will not be updated to add `pixi` to it. | |
130130
| `PIXI_DOWNLOAD_URL` | Overrides the download URL for the Pixi binary (useful for mirrors or custom builds). | GitHub releases, e.g. [linux-64](https://github.com/prefix-dev/pixi/releases/latest/download/pixi-x86_64-unknown-linux-musl.tar.gz) |
131+
| `NETRC` | Path to a custom `.netrc` file for authentication with private repositories. | |
131132
| `TMP_DIR` | The temporary directory the script uses to download to and unpack the binary from. | `/tmp` |
132133

133134
For example, on Apple Silicon, you can force the installation of the x86 version:
@@ -139,6 +140,35 @@ its [compile steps](https://github.com/conda/rattler/tree/main#give-it-a-try).
139140
curl -fsSL https://pixi.sh/install.sh | PIXI_VERSION=v0.18.0 bash
140141
```
141142

143+
#### Using `.netrc` for Authentication
144+
145+
If you need to download Pixi from a private repository that requires authentication, you can use a `.netrc` file instead of hardcoding credentials in the `PIXI_DOWNLOAD_URL`.
146+
147+
The install script automatically uses `.netrc` for authentication with `curl` and `wget`. By default, it looks for `~/.netrc`. You can specify a custom location using the `NETRC` environment variable:
148+
149+
```shell
150+
# Use the default ~/.netrc file
151+
curl -fsSL https://pixi.sh/install.sh | PIXI_DOWNLOAD_URL=https://private.example.com/pixi-latest.tar.gz bash
152+
```
153+
154+
```shell
155+
# Use a custom .netrc file
156+
curl -fsSL https://pixi.sh/install.sh | NETRC=/path/to/custom/.netrc PIXI_DOWNLOAD_URL=https://private.example.com/pixi-latest.tar.gz bash
157+
```
158+
159+
Your `.netrc` file should contain credentials in the following format:
160+
```
161+
machine private.example.com
162+
login your-username
163+
password your-token-or-password
164+
```
165+
166+
!!! tip "Security Recommendation"
167+
Using `.netrc` is more secure than embedding credentials directly in the `PIXI_DOWNLOAD_URL` (e.g., `https://user:[email protected]/file`), as it keeps credentials separate from the URL and prevents them from appearing in logs or process listings.
168+
169+
!!! tip "Security Note"
170+
The install script automatically masks any credentials embedded in the download URL when displaying messages, replacing them with `***:***@` to prevent credentials from appearing in logs or console output.
171+
142172
=== "Windows"
143173

144174
The installation script has several options that can be manipulated through environment variables.
@@ -155,6 +185,17 @@ its [compile steps](https://github.com/conda/rattler/tree/main#give-it-a-try).
155185
$env:PIXI_VERSION='v0.18.0'; powershell -ExecutionPolicy Bypass -Command "iwr -useb https://pixi.sh/install.ps1 | iex"
156186
```
157187

188+
#### Authentication for Private Repositories
189+
190+
If you need to download Pixi from a private repository that requires authentication, you can embed credentials in the `PIXI_DOWNLOAD_URL`. The install script will automatically mask credentials in its output for security.
191+
192+
```powershell
193+
$env:PIXI_DOWNLOAD_URL='https://username:[email protected]/pixi-latest.zip'; powershell -ExecutionPolicy Bypass -Command "iwr -useb https://pixi.sh/install.ps1 | iex"
194+
```
195+
196+
!!! tip "Security Note"
197+
The PowerShell install script automatically masks any credentials embedded in the download URL when displaying messages, replacing them with `***:***@` to prevent credentials from appearing in logs or console output.
198+
158199
## Autocompletion
159200

160201
To get autocompletion follow the instructions for your shell.

install/install.ps1

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ param (
3333

3434
Set-StrictMode -Version Latest
3535

36+
function Mask-Credentials {
37+
param(
38+
[string] $Url
39+
)
40+
# Replace username:password@ pattern with ***:***@
41+
return $Url -replace '://[^:@/]+:[^@/]+@', '://***:***@'
42+
}
43+
3644
function Publish-Env {
3745
if (-not ("Win32.NativeMethods" -as [Type])) {
3846
Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @"
@@ -176,7 +184,7 @@ if ($Env:PIXI_DOWNLOAD_URL) {
176184
$BinDir = Join-Path $PixiHome 'bin'
177185

178186
Write-Host "This script will automatically download and install Pixi ($PixiVersion) for you."
179-
Write-Host "Getting it from this url: $DOWNLOAD_URL"
187+
Write-Host "Getting it from this url: $(Mask-Credentials $DOWNLOAD_URL)"
180188
Write-Host "The binary will be installed into '$BinDir'"
181189

182190
$TEMP_FILE = [System.IO.Path]::GetTempFileName()
@@ -195,7 +203,7 @@ try {
195203
# Extract pixi from the downloaded zip file
196204
Expand-Archive -Path $ZIP_FILE -DestinationPath $BinDir -Force
197205
} catch {
198-
Write-Host "Error: '$DOWNLOAD_URL' is not available or failed to download"
206+
Write-Host "Error: '$(Mask-Credentials $DOWNLOAD_URL)' is not available or failed to download"
199207
exit 1
200208
} finally {
201209
Remove-Item -Path $ZIP_FILE

install/install.sh

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,27 @@ set -eu
33
# Version: v0.59.0
44

55
__wrap__() {
6+
# Function to mask username and password in URLs for safe printing
7+
# Usage: mask_credentials "url"
8+
# Returns the URL with credentials replaced by ***:***@
9+
#
10+
# [^:@/]+ - This matches the username part:
11+
# - [^:@/] means "any character EXCEPT :, @, or /"
12+
# - + means "one or more of these characters"
13+
# - So it captures everything up until it hits a colon, at-sign, or slash
14+
# - : - Matches the literal colon that separates username from password
15+
#
16+
# [^@/]+ - This matches the password part:
17+
# - [^@/] means "any character EXCEPT @ or /"
18+
# - + means "one or more of these characters"
19+
# - So it captures everything after the colon until it hits an at-sign or slash
20+
# - @ - Matches the literal at-sign that
21+
mask_credentials() {
22+
URL="$1"
23+
# Use sed to replace username:password@ pattern with ***:***@
24+
echo "$URL" | sed -E 's|://[^:@/]+:[^@/]+@|://***:***@|g'
25+
}
26+
627
VERSION="${PIXI_VERSION:-latest}"
728
PIXI_HOME="${PIXI_HOME:-$HOME/.pixi}"
829
case "$PIXI_HOME" in
@@ -44,7 +65,7 @@ __wrap__() {
4465
DOWNLOAD_URL="${PIXI_DOWNLOAD_URL:-${REPOURL%/}/releases/download/v${VERSION#v}/${BINARY}${EXTENSION-}}"
4566
fi
4667

47-
printf "This script will automatically download and install Pixi (%s) for you.\nGetting it from this url: %s\n" "$VERSION" "$DOWNLOAD_URL"
68+
printf "This script will automatically download and install Pixi (%s) for you.\nGetting it from this url: %s\n" "$VERSION" "$(mask_credentials "$DOWNLOAD_URL")"
4869

4970
HAVE_CURL=false
5071
HAVE_CURL_8_8_0=false
@@ -93,33 +114,46 @@ __wrap__() {
93114
WGET_OPTIONS="--show-progress"
94115
fi
95116

117+
# Use .netrc for authentication - prioritize NETRC env var over default location
118+
if [ -n "${NETRC:-}" ]; then
119+
CURL_OPTIONS="$CURL_OPTIONS --netrc-file $NETRC"
120+
WGET_OPTIONS="$WGET_OPTIONS --netrc-file=$NETRC"
121+
elif [ -f "$HOME/.netrc" ]; then
122+
CURL_OPTIONS="$CURL_OPTIONS --netrc"
123+
WGET_OPTIONS="$WGET_OPTIONS --netrc"
124+
fi
125+
96126
if $HAVE_CURL; then
97127
CURL_ERR=0
98128
HTTP_CODE="$(curl -SL $CURL_OPTIONS "$DOWNLOAD_URL" --output "$TEMP_FILE" --write-out "%{http_code}")" || CURL_ERR=$?
99129
case "$CURL_ERR" in
100130
35 | 53 | 54 | 59 | 66 | 77)
101131
if ! $HAVE_WGET; then
102-
echo "error: when download '${DOWNLOAD_URL}', curl has some local ssl problems with error $CURL_ERR" >&2
132+
echo "error: when download '$(mask_credentials "$DOWNLOAD_URL")', curl has some local ssl problems with error $CURL_ERR" >&2
103133
exit 1
104134
fi
105135
# fallback to wget
106136
;;
107137
0)
108-
if [ "${HTTP_CODE}" -lt 200 ] || [ "${HTTP_CODE}" -gt 299 ]; then
109-
echo "error: '${DOWNLOAD_URL}' is not available" >&2
138+
if [ "${HTTP_CODE}" -eq 401 ]; then
139+
echo "error: authentication failed when downloading '$(mask_credentials "$DOWNLOAD_URL")'" >&2
140+
echo " Check your .netrc file, NETRC environment variable, or the hardcoded credentials in PIXI_DOWNLOAD_URL." >&2
141+
exit 1
142+
elif [ "${HTTP_CODE}" -lt 200 ] || [ "${HTTP_CODE}" -gt 299 ]; then
143+
echo "error: '$(mask_credentials "$DOWNLOAD_URL")' is not available (HTTP ${HTTP_CODE})" >&2
110144
exit 1
111145
fi
112146
HAVE_WGET=false # download success, skip wget
113147
;;
114148
*)
115-
echo "error: when download '${DOWNLOAD_URL}', curl fails with with error $CURL_ERR" >&2
149+
echo "error: when download '$(mask_credentials "$DOWNLOAD_URL")', curl fails with error $CURL_ERR" >&2
116150
exit 1
117151
;;
118152
esac
119153
fi
120154

121155
if $HAVE_WGET && ! wget $WGET_OPTIONS --output-document="$TEMP_FILE" "$DOWNLOAD_URL"; then
122-
echo "error: '${DOWNLOAD_URL}' is not available" >&2
156+
echo "error: '$(mask_credentials "$DOWNLOAD_URL")' is not available" >&2
123157
exit 1
124158
fi
125159

0 commit comments

Comments
 (0)