Repository: pantsbuild/pants

Issue:
docker_image secrets doesn't expanduser
**Describe the bug**
When defining secrets on a `docker_image` target, paths starting with `~` are not respected.
For example:
```
docker_image(
  secrets={
    mysecret="~/.secret"
  }
)
```

Leads to an error: `ERROR: failed to stat <pwd>/~/.secret: stat <pwd>/~/.secret: no such file or directory`.

**Pants version**
2.15.0

**OS**
MacOS




Discussion:

Resolving patch:
diff --git a/src/python/pants/backend/docker/target_types.py b/src/python/pants/backend/docker/target_types.py
--- a/src/python/pants/backend/docker/target_types.py
+++ b/src/python/pants/backend/docker/target_types.py
@@ -282,8 +282,9 @@ class DockerImageBuildSecretsOptionField(
         Secret files to expose to the build (only if BuildKit enabled).
 
         Secrets may use absolute paths, or paths relative to your build root, or the BUILD file
-        if prefixed with `./`. The id should be valid as used by the Docker build `--secret`
-        option. See [Docker secrets](https://docs.docker.com/engine/swarm/secrets/) for more
+        if prefixed with `./`. Paths to your home directory will be automatically expanded.
+        The id should be valid as used by the Docker build `--secret` option.
+        See [Docker secrets](https://docs.docker.com/engine/swarm/secrets/) for more
         information.
 
         Example:
@@ -292,6 +293,7 @@ class DockerImageBuildSecretsOptionField(
                 secrets={
                     "mysecret": "/var/secrets/some-secret",
                     "repo-secret": "src/proj/secrets/some-secret",
+                    "home-dir-secret": "~/.config/some-secret",
                     "target-secret": "./secrets/some-secret",
                 }
             )
@@ -308,8 +310,9 @@ def option_values(self, **kwargs) -> Iterator[str]:
             full_path = os.path.join(
                 get_buildroot(),
                 self.address.spec_path if re.match(r"\.{1,2}/", path) else "",
-                path,
+                os.path.expanduser(path),
             )
+
             yield f"id={secret},src={os.path.normpath(full_path)}"
 
 


Test patch:
diff --git a/src/python/pants/backend/docker/target_types_test.py b/src/python/pants/backend/docker/target_types_test.py
new file mode 100644
--- /dev/null
+++ b/src/python/pants/backend/docker/target_types_test.py
@@ -0,0 +1,36 @@
+# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).
+# Licensed under the Apache License, Version 2.0 (see LICENSE).
+import os
+from pathlib import Path
+
+import pytest
+
+from pants.backend.docker.target_types import DockerImageBuildSecretsOptionField
+from pants.engine.internals.native_engine import Address
+
+
+@pytest.mark.parametrize(
+    "src, expected",
+    [
+        (
+            "/aboslute/path",
+            "/aboslute/path",
+        ),
+        (
+            "./relative/path",
+            str(Path.cwd().joinpath("./relative/path")),
+        ),
+        (
+            "~/home/path",
+            os.path.expanduser("~/home/path"),
+        ),
+    ],
+)
+def test_secret_path_resolvement(src: str, expected: str):
+    Path.cwd().joinpath("pants.toml").write_text("")
+    secrets_option_field = DockerImageBuildSecretsOptionField(
+        {"mysecret": src}, address=Address("")
+    )
+    values = list(secrets_option_field.option_values())
+
+    assert values == [f"id=mysecret,src={expected}"]