fix: keep logged package publish metadata on a single line (#3447)

The resolve step echoes the publish command with shlex.quote, which is shell
quoting rather than output escaping: it wraps a value holding a line break in
single quotes and leaves the break itself intact. A caller-supplied changelog,
categories or topics value carrying a newline therefore opened a second line
in the step log, and the runner parses each stdout line, so that second line
reached it as a workflow command.

Escape the parts that are not printable in the echo. The re-runnable .sh file
keeps plain shell quoting, because there the quoting is what makes the script
correct.
This commit is contained in:
Yiğit ERDOĞAN
2026-08-11 10:52:24 -07:00
committed by GitHub
parent 8b31a7e6e1
commit 8bf424cff1
2 changed files with 31 additions and 1 deletions
+12 -1
View File
@@ -363,6 +363,15 @@ jobs:
from urllib.parse import quote, urlparse
from urllib.request import Request, urlopen
def quote_for_log(part):
# shlex.quote is shell quoting, not output escaping: it wraps a value holding a
# line break in single quotes and leaves the break itself intact. One newline in
# a caller's metadata would then open a second log line, which the runner reads
# as a ::workflow-command. json.dumps escapes every control character, so one
# publish stays one line however the caller fills changelog, categories or topics.
quoted = shlex.quote(part)
return quoted if quoted.isprintable() else json.dumps(part)
def split_ref_path(value):
if not value:
return "", ""
@@ -572,7 +581,9 @@ jobs:
shell_line = " ".join(shlex.quote(part) for part in cmd)
path.write_text("#!/usr/bin/env bash\nset -euo pipefail\n" + shell_line + "\n", encoding="utf-8")
path.chmod(0o755)
print(shell_line)
# Log-only: the file above is what a maintainer re-runs, so it keeps plain shell
# quoting. This echo does not, because the runner parses each stdout line.
print(" ".join(quote_for_log(part) for part in cmd))
def write_output(fh, name, value):
delimiter = f"ghadelimiter_{uuid.uuid4().hex}"