Skip to content

Commit 9975d47

Browse files
Process backslashes inside quoted shell string literals (#524)
Process backslashes inside quoted shell string literals Reviewed-by: gemini-code-assist[bot] Reviewed-by: Nikola Forró Reviewed-by: Laura Barcziová
2 parents 324555d + 77afb3d commit 9975d47

2 files changed

Lines changed: 42 additions & 1 deletion

File tree

specfile/sanitizer.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,29 @@ def sanitize_shell_expansion(body: str) -> str:
345345
Sanitized shell expansion body, or %{nil} if sanitization is not possible.
346346
"""
347347

348+
def unescape_quoted_backslashes(s):
349+
# process backslashes inside quoted shell string literals
350+
try:
351+
lex = shlex.shlex(s, posix=False)
352+
lex.whitespace_split = True
353+
lex.commenters = ""
354+
parts = []
355+
for token in lex:
356+
if (
357+
len(token) >= 2
358+
and token[0] in ("'", '"')
359+
and token[-1] == token[0]
360+
):
361+
inner = token[1:-1].replace("\\\\", "\\")
362+
parts.append(token[0] + inner + token[0])
363+
else:
364+
parts.append(token)
365+
return " ".join(parts)
366+
except ValueError:
367+
return s
368+
369+
body = unescape_quoted_backslashes(body)
370+
348371
def strip_quotes(s):
349372
s = s.strip()
350373
if len(s) >= 2 and s[0] in "'\"" and s[-1] == s[0]:
@@ -1069,5 +1092,10 @@ def sanitize_nodes(nodes):
10691092
i += 1
10701093
return "".join(result)
10711094

1072-
sanitized = sanitize_nodes(ValueParser.parse(value))
1095+
try:
1096+
nodes = ValueParser.parse(value)
1097+
except Exception:
1098+
return "%{nil}", 0, 1
1099+
else:
1100+
sanitized = sanitize_nodes(nodes)
10731101
return sanitized, converted, removed

tests/unit/test_sanitizer.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,10 @@ def test_pipe_to_tr(body, expected):
323323
"echo 1.2.3-rc4 | sed 's/-/~/g'",
324324
'%{lua:print((rpm.expand("%{quote:1.2.3-rc4}"):gsub("-", "~")))}',
325325
),
326+
(
327+
"echo %{version} | sed 's/\\\\./_/g'",
328+
'%{lua:print((rpm.expand("%{version}"):gsub("%.", "_")))}',
329+
),
326330
],
327331
)
328332
def test_pipe_to_sed(body, expected):
@@ -338,6 +342,15 @@ def test_chained_sed():
338342
)
339343

340344

345+
def test_chained_sed_rpm_escaped():
346+
assert Sanitizer.sanitize_shell_expansion(
347+
"echo '%canonical_project_name' | sed --regexp-extended 's:-:_:g;s:\\\\.:_:g'"
348+
) == (
349+
'%{lua:local v=(rpm.expand("%{canonical_project_name}"):gsub("-", "_"))'
350+
' print((v:gsub("%.", "_")))}'
351+
)
352+
353+
341354
@pytest.mark.parametrize(
342355
"body, expected",
343356
[

0 commit comments

Comments
 (0)