appleboy / appleboy/ssh-action
entrypoint.sh: closing EOF delimiter never written to $GITHUB_OUTPUT when capture_stdout=true and remote command fails
- Dominant language
- Shell
- Stars
- 6.2k
- Forks
- 679
- Avg merge
- 35m
- Merged PRs (30d)
- 1
Description
## Summary
When `capture_stdout: true` and the remote command exits non-zero, `entrypoint.sh` dies (via `set -e` +
`pipefail`) **before** writing the closing `EOF` delimiter to `$GITHUB_OUTPUT`. The GitHub Actions
runner then fails the step with a confusing secondary error that masks the real remote command failure:
```
Error: Unable to process file command 'output' successfully.
Invalid value. Matching delimiter not found 'EOF'
```
## Root cause
`entrypoint.sh` (pinned `0ff4204d59e8e51228ff73bce53f80d53301dee2`, v1.2.5):
```bash
set -euo pipefail
...
if [[ "${INPUT_CAPTURE_STDOUT}" == 'true' ]]; then
echo 'stdout<> "${GITHUB_OUTPUT}"
"${TARGET}" "$@" | tee -a "${GITHUB_OUTPUT}"
echo 'EOF' >> "${GITHUB_OUTPUT}"
else
"${TARGET}" "$@"
fi
```
With `pipefail`, if `${TARGET}` (drone-ssh, running the user's remote command) exits non-zero, the
whole `TARGET | tee` pipeline returns non-zero. With `set -e` also active, the script exits right there
— the next line (`echo 'EOF' >> "${GITHUB_OUTPUT}"`) never runs. The output file ends up with the
opening `stdout<> "${GITHUB_OUTPUT}"
"$@" | tee -a "${GITHUB_OUTPUT}"
echo 'EOF' >> "${GITHUB_OUTPUT}"
}
fail_like_remote_command() { echo "some real error"; exit 1; }
GITHUB_OUTPUT=/tmp/mock_output.txt
: > "$GITHUB_OUTPUT"
run_entrypoint_snippet fail_like_remote_command
cat "$GITHUB_OUTPUT"
```
Output: `stdout<.outputs.stdout` being valid on the failure path
breaks silently (in our case, a diagnostics-extraction step that never runs with useful data).
## Suggested fix
Write the closing delimiter unconditionally, regardless of `${TARGET}`'s exit code — e.g. capture the
pipe's exit status via `${PIPESTATUS[0]}` instead of relying on `set -e`/`pipefail` to propagate it, and
explicitly `exit` with that status only *after* the closing `echo 'EOF' >> "${GITHUB_OUTPUT}"`:
```bash
if [[ "${INPUT_CAPTURE_STDOUT}" == 'true' ]]; then
echo 'stdout<> "${GITHUB_OUTPUT}"
set +e
"${TARGET}" "$@" | tee -a "${GITHUB_OUTPUT}"
status="${PIPESTATUS[0]}"
set -e
echo 'EOF' >> "${GITHUB_OUTPUT}"
exit "${status}"
else
"${TARGET}" "$@"
fi
```
Happy to open a PR with this if useful — wanted to confirm the root cause and preferred fix shape first.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in entrypoint.sh, focusing on the capture_stdout branch and its TARGET | tee pipeline under set -euo pipefail. Reproduce the failure with the isolated shell snippet, then verify that a failed remote command still writes the closing EOF delimiter to GITHUB_OUTPUT while preserving the command's non-zero status.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github-actions, shell
- Domain
- ci-cd, devops
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 82/100