From 6794e66c4d7cf35b4bd1c8c780e43ad041a6e2c8 Mon Sep 17 00:00:00 2001 From: Minseong Choi Date: Tue, 22 Sep 2026 13:53:03 +0900 Subject: [PATCH] fix(bootstrap): fail a tokenless private clone instead of prompting A source build against a private repository with no FELIS_GITHUB_TOKEN, or a wrong one, made git ask for a username on /dev/tty, and a piped install sat there waiting. git_auth now runs git with GIT_TERMINAL_PROMPT=0 on both arms, so git fails at once with "terminal prompts disabled". Both fetch_source failures name FELIS_GITHUB_TOKEN in their message: the fresh clone, and the fetch into an existing checkout, which had no message of its own before. --- deploy/bootstrap.sh | 13 ++++++++---- deploy/bootstrap_test.sh | 43 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/deploy/bootstrap.sh b/deploy/bootstrap.sh index eff72f3..c909937 100644 --- a/deploy/bootstrap.sh +++ b/deploy/bootstrap.sh @@ -988,12 +988,16 @@ download_release_binary() { # approve that follows a successful auth, so it outlives the install after all. An empty # value is git's documented list reset. Verified on Fedora: with store configured the single # -c form persists the token to disk, the reset form writes nothing. +# +# GIT_TERMINAL_PROMPT=0 on both arms: GitHub answers a private repo with no or a bad token +# by asking for credentials, and git would put that prompt on /dev/tty, where a piped +# install sits waiting instead of failing with the FELIS_GITHUB_TOKEN hint. git_auth() { if [ -n "$FELIS_GITHUB_TOKEN" ]; then - git -c 'credential.helper=' \ + GIT_TERMINAL_PROMPT=0 git -c 'credential.helper=' \ -c 'credential.helper=!f() { printf "username=x-access-token\npassword=%s\n" "$FELIS_GITHUB_TOKEN"; }; f' "$@" else - git "$@" + GIT_TERMINAL_PROMPT=0 git "$@" fi } @@ -1070,7 +1074,8 @@ fetch_source() { resolve_install_ref if [ -d "${SRC_DIR}/.git" ]; then log "updating source in ${SRC_DIR}" - git_auth -C "$SRC_DIR" fetch --depth 1 origin "$FELIS_REF" + git_auth -C "$SRC_DIR" fetch --depth 1 origin "$FELIS_REF" \ + || die "could not fetch ${FELIS_REF} from ${FELIS_REPO_URL}; if the repository is private, set FELIS_GITHUB_TOKEN to a token with read access to it" git -C "$SRC_DIR" checkout -f FETCH_HEAD else log "cloning ${FELIS_REPO_URL} (${FELIS_REF})" @@ -1082,7 +1087,7 @@ fetch_source() { git_auth clone --depth 1 --branch "$FELIS_REF" "$FELIS_REPO_URL" "$SRC_DIR" 2>/dev/null \ || { git_auth clone "$FELIS_REPO_URL" "$SRC_DIR" \ && git_auth -C "$SRC_DIR" checkout -f "$FELIS_REF"; } \ - || die "could not check out ${FELIS_REF} from ${FELIS_REPO_URL}" + || die "could not check out ${FELIS_REF} from ${FELIS_REPO_URL}; if the repository is private, set FELIS_GITHUB_TOKEN to a token with read access to it" fi stamp_version ok "source ready at ${SRC_DIR}" diff --git a/deploy/bootstrap_test.sh b/deploy/bootstrap_test.sh index d5af411..9e2fc8a 100644 --- a/deploy/bootstrap_test.sh +++ b/deploy/bootstrap_test.sh @@ -426,6 +426,49 @@ gtmp="$(printf '%s\n' "$out" | sed -n 's/^TEMP: //p')" expect "the Go download is staged in a directory the cleanup removes" \ "CURL: ${gtmp:-}/go1.26.4.linux-amd64.tar.gz" "$out" +# --- a private repo without a token fails with the hint instead of prompting ------------- +# git asks for credentials on /dev/tty, where a piped install would sit waiting. Every +# network git call goes through git_auth, so the switch belongs there. + +gablock="$(awk '/^git_auth\(\) \{/,/^}/' "$BS")" +[ -n "$gablock" ] || { echo "FAIL: no git_auth found in $BS"; exit 1; } +[ "$(printf '%s\n' "$gablock" | wc -l)" -lt 15 ] \ + || { echo "FAIL: the extracted block is not the function -- did its closing brace move?"; exit 1; } + +run_git_auth() { # token + FELIS_GITHUB_TOKEN="$1" bash -c ' + unset GIT_TERMINAL_PROMPT # whatever runs this harness may have set it already + git() { printf "GIT: prompt=%s\n" "${GIT_TERMINAL_PROMPT:-}"; } + '"$gablock"' + git_auth clone https://example.invalid/felis.git' +} + +expect "git never prompts without a token" "GIT: prompt=0" "$(run_git_auth '')" +expect "git never prompts with a token" "GIT: prompt=0" "$(run_git_auth ghp_example)" + +fblock="$(awk '/^fetch_source\(\) \{/,/^}/' "$BS")" +[ -n "$fblock" ] || { echo "FAIL: no fetch_source found in $BS"; exit 1; } +[ "$(printf '%s\n' "$fblock" | wc -l)" -lt 40 ] \ + || { echo "FAIL: the extracted block is not the function -- did its closing brace move?"; exit 1; } + +run_fetch() { # src-dir + SRC_DIR="$1" FELIS_REF=main FELIS_REPO_URL=https://example.invalid/felis.git bash -c ' + die() { printf "DIE: %s\n" "$*"; exit 1; } + log() { :; } + ok() { :; } + resolve_install_ref() { :; } + stamp_version() { :; } + git_auth() { return 128; } + git() { :; } + '"$fblock"' + fetch_source' +} + +expect "a failed clone names the token" "set FELIS_GITHUB_TOKEN" "$(run_fetch "$sdir/src")" +mkdir -p "$sdir/src/.git" +expect "a failed fetch into an existing checkout names the token" "set FELIS_GITHUB_TOKEN" \ + "$(run_fetch "$sdir/src")" + # --------------------------------------------------------------------------------------- if [ "$fails" -eq 0 ]; then echo "ALL PASS"