Repository: pantsbuild/pants

Issue:
`pex_binary().args` are not properly escaped. 
**Describe the bug**
If you attempt to inject any `--args`, `pex` will complain like:
```
pex: error: argument --inject-args: expected one argument
```

**Pants version**
2.16.0rc0


**Additional info**
[Slack thread](https://pantsbuild.slack.com/archives/C0D7TNJHL/p1682003882696899)

These args needs to be escaped:
https://github.com/pantsbuild/pants/blob/1aca34961105f98c2dd63addd37f9e5cfc49ee9b/src/python/pants/backend/python/util_rules/pex.py#L586-L587

Introduced in #17905



Discussion:
Example repro:
```python
pex_binary(
    name="inference-server",
    layout="packed",
    include_tools=True,
    dependencies=["./ackbar/inference_server"],
    platforms=["linux_x86_64-cp-310-cp310"],
    script="uvicorn",
    args=["ackbar.inference_server.app:app", "--host", "0.0.0.0", "--port", "8080"],
)
```
The escaping will work but it confuses me at least as to whether it does - I had to test. Another way to fix is to `f"--inject-args={injected_arg}"`, which, at least to me, much more clearly always works.

Resolving patch:
diff --git a/src/python/pants/backend/python/util_rules/pex.py b/src/python/pants/backend/python/util_rules/pex.py
--- a/src/python/pants/backend/python/util_rules/pex.py
+++ b/src/python/pants/backend/python/util_rules/pex.py
@@ -615,10 +615,10 @@ async def build_pex(
     if request.main is not None:
         argv.extend(request.main.iter_pex_args())
 
-    for injected_arg in request.inject_args:
-        argv.extend(["--inject-args", str(injected_arg)])
-    for k, v in sorted(request.inject_env.items()):
-        argv.extend(["--inject-env", f"{k}={v}"])
+    argv.extend(
+        f"--inject-args={shlex.quote(injected_arg)}" for injected_arg in request.inject_args
+    )
+    argv.extend(f"--inject-env={k}={v}" for k, v in sorted(request.inject_env.items()))
 
     # TODO(John Sirois): Right now any request requirements will shadow corresponding pex path
     #  requirements, which could lead to problems. Support shading python binaries.


Test patch:
diff --git a/src/python/pants/backend/python/goals/package_pex_binary_integration_test.py b/src/python/pants/backend/python/goals/package_pex_binary_integration_test.py
--- a/src/python/pants/backend/python/goals/package_pex_binary_integration_test.py
+++ b/src/python/pants/backend/python/goals/package_pex_binary_integration_test.py
@@ -177,8 +177,8 @@ def test_layout(rule_runner: RuleRunner, layout: PexLayout) -> None:
                 """\
                 import os
                 import sys
-                print(f"FOO={os.environ.get('FOO')}")
-                print(f"BAR={os.environ.get('BAR')}")
+                for env in ["FOO", "--inject-arg", "quotes '"]:
+                    print(f"{env}={os.environ.get(env)}")
                 print(f"ARGV={sys.argv[1:]}")
                 """
             ),
@@ -187,8 +187,8 @@ def test_layout(rule_runner: RuleRunner, layout: PexLayout) -> None:
                 python_sources(name="lib")
                 pex_binary(
                     entry_point="app.py",
-                    args=['123', 'abc'],
-                    env={{'FOO': 'xxx', 'BAR': 'yyy'}},
+                    args=['123', 'abc', '--inject-env', "quotes 'n spaces"],
+                    env={{'FOO': 'xxx', '--inject-arg': 'yyy', "quotes '": 'n spaces'}},
                     layout="{layout.value}",
                 )
                 """
@@ -212,8 +212,9 @@ def test_layout(rule_runner: RuleRunner, layout: PexLayout) -> None:
     stdout = dedent(
         """\
         FOO=xxx
-        BAR=yyy
-        ARGV=['123', 'abc']
+        --inject-arg=yyy
+        quotes '=n spaces
+        ARGV=['123', 'abc', '--inject-env', "quotes 'n spaces"]
         """
     ).encode()
     assert stdout == subprocess.run([executable], check=True, stdout=subprocess.PIPE).stdout