diff --git a/.tests/e2e.sh b/.tests/e2e.sh index 8878a4e..95a1d40 100755 --- a/.tests/e2e.sh +++ b/.tests/e2e.sh @@ -40,6 +40,15 @@ trap cleanup EXIT INT TERM printf 'Bootstrap URL (paste from Bitwarden): ' >&2 IFS= read -r BOOT_URL [ -n "$BOOT_URL" ] || { echo "no URL given"; exit 1; } +# Normalise exactly as dotup does, and for the same reason: the rotation scripts +# print the full file URL, so that is what Bitwarden holds and what gets pasted. +# This wrapper appends /bootstrap.env below, so without stripping it first the +# request becomes .../bootstrap.env/bootstrap.env and the preflight reports +# "wrong password, wrong route, or endpoint down" -- blaming the credentials for +# a URL shape, which is the precise failure dotup was just fixed to stop doing. +# Caught by running this harness with the file URL rather than the directory. +BOOT_URL=${BOOT_URL%/} +BOOT_URL=${BOOT_URL%/bootstrap.env} printf 'Username [ben]: ' >&2 IFS= read -r BOOT_USER diff --git a/.tests/test.sh b/.tests/test.sh index 17c181c..4404990 100755 --- a/.tests/test.sh +++ b/.tests/test.sh @@ -162,6 +162,21 @@ is "…and leaves a credential-free remote untouched" \ is "…including scp-style ssh" \ " git@git.example.com:ben/x.git" \ "$(split 'git@git.example.com:ben/x.git')" +# The bootstrap URL a human pastes comes from Bitwarden, where the rotation +# scripts put the FULL file URL. dotup appends /bootstrap.env itself, so without +# normalisation that becomes .../bootstrap.env/bootstrap.env -- a 404 that +# curl --fail turns into "endpoint refused the credentials", blaming the +# password for a URL shape. Both forms must land on the same request. +norm() { P_URL=$1; eval "$(sed -n '/^\tP_URL=\${P_URL%\//p;/^\tP_URL=\${P_URL%\/bootstrap.env}/p' $D)" + printf '%s\n' "${P_URL%/}/bootstrap.env"; } +is "a directory URL resolves to the blob" "https://h/r/bootstrap.env" \ + "$(norm 'https://h/r/')" +is "...without a trailing slash too" "https://h/r/bootstrap.env" \ + "$(norm 'https://h/r')" +is "...and the full file URL, which is what Bitwarden holds" "https://h/r/bootstrap.env" \ + "$(norm 'https://h/r/bootstrap.env')" +is "...even with a trailing slash on the file URL" "https://h/r/bootstrap.env" \ + "$(norm 'https://h/r/bootstrap.env/')" rd() { eval "$(sed -n '/^redact_url()/p' $D)"; redact_url "$1"; } is "redact_url strips userinfo" "https://@git.example.com/x.git" \ "$(rd 'https://ben:deadbeefcafe@git.example.com/x.git')" diff --git a/dot_local/bin/executable_dotup b/dot_local/bin/executable_dotup index 9754786..f8adbc1 100755 --- a/dot_local/bin/executable_dotup +++ b/dot_local/bin/executable_dotup @@ -784,6 +784,13 @@ cmd_private() { P_URL=''; P_USER=''; P_PW='' printf ' Bootstrap URL: ' >&2; IFS= read -r P_URL || : [ -n "$P_URL" ] || { say " public-only machine. Nothing was asked for."; return 0; } + # Accept the directory OR the full file URL, because both are in circulation: + # the rotation scripts print the file form and say to store THAT in Bitwarden, + # so pasting what you saved is the likely case. Without this, the request + # becomes .../bootstrap.env/bootstrap.env, the 404 trips curl --fail, and the + # error below blames the credentials for what is actually a URL shape. + P_URL=${P_URL%/} + P_URL=${P_URL%/bootstrap.env} printf ' Username: ' >&2; IFS= read -r P_USER || : printf ' Password: ' >&2 stty -echo 2>/dev/null || :; IFS= read -r P_PW || :; stty echo 2>/dev/null || :; printf '\n' >&2