Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/28.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Strip CRLF line endings from environment variable values, which GitHub's web form stores when editing multi-line secrets. Values are reported as processed.
24 changes: 20 additions & 4 deletions scripts/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ configure_ssh_key() {

# Parse a NAME=VALUE file and export every entry. $1 is the file to read.
load_env_file() {
local source_file="$1" env_file_len line
local source_file="$1" env_file_len line cr_lines=0
env_file_len=$(grep -cv -e '^#' -e '^$' "${source_file}" || true)
if [[ ${env_file_len} -gt 0 ]]; then
echo "Environment Variables: Additional values"
Expand All @@ -73,10 +73,17 @@ load_env_file() {
# Values are taken verbatim, matching `docker --env-file`: quotes in the
# file are part of the value, not delimiters around it.
#
# The ENV_FILE input has no trailing newline, so the `-n` test is what
# keeps the final line from being dropped by read's non-zero exit. A file
# read through env_file_path usually does end in a newline; both work.
# Strip trailing carriage returns from CRLF line endings (GitHub's web form
# stores multi-line secrets with CRLF). The ENV_FILE input has no trailing
# newline, so the `-n` test is what keeps the final line from being dropped
# by read's non-zero exit. A file read through env_file_path usually does
# end in a newline; both work.
while IFS= read -r line || [ -n "${line}" ]; do
# Remove trailing \r if present (from CRLF line endings)
if [[ "${line}" == *$'\r' ]]; then
line="${line%$'\r'}"
((++cr_lines))
fi
case "${line}" in
''|\#*) continue ;;
esac
Expand All @@ -86,6 +93,15 @@ load_env_file() {
fi
export "${line?}"
done < "${source_file}"
if [ ${cr_lines} -gt 0 ]; then
# Reported unconditionally, not only under DEBUG: the whole problem with
# CRLF is that it is invisible everywhere else.
if [ ${cr_lines} -eq 1 ]; then
echo "Environment Variables: removed carriage returns from 1 line"
else
echo "Environment Variables: removed carriage returns from ${cr_lines} lines"
fi
fi
if [ "${DEBUG}" != "0" ]; then
echo "Environment vars after: $(env|wc -l)"
fi
Expand Down
107 changes: 107 additions & 0 deletions tests/entrypoint.bats
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,70 @@ export_from_env_file() {
[[ "$output" == *"is not in NAME=VALUE format"* ]]
}

# --- env_file CRLF handling (issue #28) -----------------------------------------------

@test "env_file strips CRLF line endings from values (issue #28)" {
# GitHub's web form saves multi-line secrets as CRLF. Every line except the
# last ends in \r, which becomes part of the value unless stripped.
# Use $'...' syntax to embed literal CRLF in the string.
export_from_env_file $'DB_USER=plone\r\nDB_PORT=5432\r\n' DB_USER
[ "$status" -eq 0 ]
[ "$output" = "plone" ]
}

@test "env_file strips CRLF from multiple values without corruption (issue #28)" {
export_from_env_file $'DB_USER=admin\r\nDB_PASS=secret\r\nDB_HOST=localhost\r\n' DB_PASS
[ "$status" -eq 0 ]
[ "$output" = "secret" ]
}

@test "env_file reports stripped carriage returns (issue #28)" {
# Like trim_inputs, the fix must report on stdout so the user sees the issue.
run env -i PATH="${PATH}" HOME="${BATS_TEST_TMPDIR}" \
ENV_FILE=$'DB_USER=plone\r\n' \
bash -c "
source '${ENTRYPOINT}'
ENV_FILE_DEST=\"\${HOME}/.env\"
configure_env_file
"
[ "$status" -eq 0 ]
[[ "$output" == *"Environment Variables: removed carriage returns from 1 line"* ]]
}

@test "env_file counts multiple CRLF strips in the report (issue #28)" {
run env -i PATH="${PATH}" HOME="${BATS_TEST_TMPDIR}" \
ENV_FILE=$'DB_USER=admin\r\nDB_PASS=secret\r\nDB_HOST=localhost\r\n' \
bash -c "
source '${ENTRYPOINT}'
ENV_FILE_DEST=\"\${HOME}/.env\"
configure_env_file
"
[ "$status" -eq 0 ]
[[ "$output" == *"Environment Variables: removed carriage returns from 3 lines"* ]]
}

@test "env_file with LF-only lines does not report carriage returns (issue #28)" {
# Verify the fix doesn't report when there are no CR chars to strip.
export_from_env_file $'DB_USER=plone\nDB_PORT=5432' DB_USER
[ "$status" -eq 0 ]
[[ ! "$output" =~ "carriage returns" ]]
}

@test "env_file with blank lines after CRLF stripping does not abort (issue #28)" {
# If a line only contained \r, after stripping it becomes empty and should
# be skipped gracefully without aborting.
export_from_env_file $'DB_USER=admin\r\n\r\nDB_PASS=secret\r\n' DB_USER
[ "$status" -eq 0 ]
[ "$output" = "admin" ]
}

@test "env_file with CRLF comment lines skips them correctly (issue #28)" {
# Comments ending in CR should still be recognized and skipped.
export_from_env_file $'# config\r\nDB_USER=plone\r\n' DB_USER
[ "$status" -eq 0 ]
[ "$output" = "plone" ]
}

# --- env_file_path (issue #3) -------------------------------------------------

# Write a file with the given content, run configure_env_file_path against it,
Expand Down Expand Up @@ -425,6 +489,49 @@ export_from_env_file_path() {
[[ "$output" == *"Input remote_host is required!"* ]]
}

# --- env_file_path CRLF handling (issue #28) -------------------------------------------------

@test "env_file_path strips CRLF line endings from values (issue #28)" {
# Files edited in Windows or via GitHub's web form may have CRLF line endings.
local file="${BATS_TEST_TMPDIR}/crlf.env"
printf '%s' "$(printf 'DB_USER=admin\r\nDB_HOST=localhost\r\n')" > "${file}"
run env -i PATH="${PATH}" HOME="${BATS_TEST_TMPDIR}" \
ENV_FILE_PATH="${file}" WANT=DB_USER \
bash -c "
source '${ENTRYPOINT}'
configure_env_file_path >/dev/null 2>&1
printf '[%s]' \"\${!WANT}\"
"
[ "$status" -eq 0 ]
[ "$output" = "[admin]" ]
}

@test "env_file_path reports stripped carriage returns (issue #28)" {
local file="${BATS_TEST_TMPDIR}/crlf.env"
printf '%s' "$(printf 'DB_USER=admin\r\nDB_PASS=secret\r\n')" > "${file}"
run env -i PATH="${PATH}" HOME="${BATS_TEST_TMPDIR}" \
ENV_FILE_PATH="${file}" \
bash -c "
source '${ENTRYPOINT}'
configure_env_file_path
"
[ "$status" -eq 0 ]
[[ "$output" == *"Environment Variables: removed carriage returns from 2 lines"* ]]
}

@test "env_file_path with LF-only lines does not report carriage returns (issue #28)" {
local file="${BATS_TEST_TMPDIR}/lf.env"
printf '%s\n' "DB_USER=admin" > "${file}"
run env -i PATH="${PATH}" HOME="${BATS_TEST_TMPDIR}" \
ENV_FILE_PATH="${file}" \
bash -c "
source '${ENTRYPOINT}'
configure_env_file_path
"
[ "$status" -eq 0 ]
[[ ! "$output" =~ "carriage returns" ]]
}

# --- scale_after --------------------------------------------------------------

@test "scale_after does nothing when unset" {
Expand Down
Loading