From bdc11a2f761e2d88db7cb1140cfbce4abae2300d Mon Sep 17 00:00:00 2001 From: butterrobot Date: Wed, 9 Sep 2026 17:58:07 +0000 Subject: [PATCH 1/2] feat: verify the key up front and stop falling back to password auth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A rejected key produced two generic "Permission denied, please try again." prompts followed by a denial listing every auth method, which says nothing about why the key was refused, and looks identical whether the key input was malformed or simply not authorized on the server. The key is now checked with ssh-keygen before connecting, so an unusable input fails immediately and says so, and the derived public key is printed — that is the exact line that has to be present in authorized_keys. BatchMode stops the interactive password fallback, and IdentitiesOnly keeps ssh from offering anything other than the supplied key. Co-Authored-By: Claude Opus 5 (1M context) --- entrypoint.sh | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/entrypoint.sh b/entrypoint.sh index 5b9786b..94d705f 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -38,10 +38,24 @@ trap 'rm -f "$KEY_FILE"' EXIT echo "$INPUT_KEY" > "$KEY_FILE" chmod 600 "$KEY_FILE" +# -P "" so an encrypted key reports a passphrase error instead of hanging on a prompt. +if ! DEPLOY_PUBLIC_KEY="$(ssh-keygen -y -P "" -f "$KEY_FILE" 2>&1)"; then + echo "Error: the 'key' input is not a usable unencrypted OpenSSH private key." >&2 + echo "ssh-keygen: ${DEPLOY_PUBLIC_KEY}" >&2 + exit 1 +fi + +# The public half is not a secret, and printing it is what makes an authentication +# failure diagnosable: it is the exact line that must be in authorized_keys. +echo "Authenticating to ${INPUT_HOST} as ${INPUT_USERNAME} with public key:" +echo " ${DEPLOY_PUBLIC_KEY}" + ssh-keyscan -p "$SSH_PORT" -H "$INPUT_HOST" >> "$KNOWN_HOSTS" 2>/dev/null +# BatchMode stops ssh falling back to interactive password auth, which otherwise +# buries a rejected key under two generic "Permission denied" prompts. rsync -avz \ - -e "ssh -i $KEY_FILE -o UserKnownHostsFile=$KNOWN_HOSTS -p $SSH_PORT -o ConnectTimeout=30" \ + -e "ssh -i $KEY_FILE -o IdentitiesOnly=yes -o BatchMode=yes -o UserKnownHostsFile=$KNOWN_HOSTS -p $SSH_PORT -o ConnectTimeout=30" \ $INPUT_ARGS \ "${SOURCE}/" \ "${INPUT_USERNAME}@${INPUT_HOST}:${INPUT_TARGET}/" -- 2.52.0 From aeb80c0565e2b93d9fc3dd99211548a20aa517db Mon Sep 17 00:00:00 2001 From: butterrobot Date: Wed, 9 Sep 2026 18:13:41 +0000 Subject: [PATCH 2/2] feat: print the deploy key fingerprint sshd names the offered key by fingerprint at LogLevel VERBOSE, so emitting it client-side makes a rejected key a direct comparison against the target's auth log rather than a guess. Co-Authored-By: Claude Opus 5 (1M context) --- entrypoint.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/entrypoint.sh b/entrypoint.sh index 94d705f..9a1a634 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -49,6 +49,9 @@ fi # failure diagnosable: it is the exact line that must be in authorized_keys. echo "Authenticating to ${INPUT_HOST} as ${INPUT_USERNAME} with public key:" echo " ${DEPLOY_PUBLIC_KEY}" +# The fingerprint is what sshd reports at LogLevel VERBOSE, so printing it here +# lets a rejected key be matched against the target's auth log directly. +echo " fingerprint: $(ssh-keygen -lf "$KEY_FILE" 2>/dev/null || echo unavailable)" ssh-keyscan -p "$SSH_PORT" -H "$INPUT_HOST" >> "$KNOWN_HOSTS" 2>/dev/null -- 2.52.0