This is an automated email from the ASF dual-hosted git repository.

imbajin pushed a commit to branch feat/oink-core-platform
in repository https://gitbox.apache.org/repos/asf/hugegraph-doc.git

commit 401134d043abcfac7e9a176f5509e46698a2b881
Author: dark <[email protected]>
AuthorDate: Fri Sep 4 22:40:33 2026 +0800

    fix(versioning): validate runner temp ancestry
    
    - inspect RUNNER_TEMP components before trusting the root
    - preserve trusted system temporary directory aliases
    - cover ancestor symlink rejection and real-root cleanup
---
 scripts/test_versioning.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++
 scripts/versioning.py      | 11 +++++-----
 2 files changed, 55 insertions(+), 6 deletions(-)

diff --git a/scripts/test_versioning.py b/scripts/test_versioning.py
index 067e18100..1216e5147 100644
--- a/scripts/test_versioning.py
+++ b/scripts/test_versioning.py
@@ -1290,6 +1290,56 @@ class VersionUrlTest(unittest.TestCase):
             self.assertEqual(sentinel.read_text(encoding="utf-8"), "keep")
             self.assertTrue(output.is_dir())
 
+    def test_output_cleanup_rejects_symlink_above_runner_temp_before_resolve(
+        self,
+    ) -> None:
+        with tempfile.TemporaryDirectory() as temp_name:
+            temp = Path(temp_name)
+            target = temp / "target"
+            runner_temp_target = target / "runner-temp"
+            output = runner_temp_target / "output"
+            output.mkdir(parents=True)
+            sentinel = output / "sentinel"
+            sentinel.write_text("keep", encoding="utf-8")
+            linked_parent = temp / "linked-parent"
+            linked_parent.symlink_to(target, target_is_directory=True)
+            runner_temp = linked_parent / "runner-temp"
+
+            with (
+                mock.patch.dict(
+                    versioning.os.environ,
+                    {"RUNNER_TEMP": str(runner_temp)},
+                ),
+                self.assertRaisesRegex(SystemExit, "symbolic link"),
+            ):
+                versioning.prepare_output_directory(
+                    runner_temp / "output",
+                    "fixture",
+                )
+
+            self.assertEqual(sentinel.read_text(encoding="utf-8"), "keep")
+            self.assertTrue(output.is_dir())
+
+    def test_output_cleanup_accepts_real_runner_temp_below_tmp_alias(
+        self,
+    ) -> None:
+        with tempfile.TemporaryDirectory(dir="/tmp") as temp_name:
+            runner_temp = Path(temp_name) / "runner-temp"
+            output = runner_temp / "output"
+            output.mkdir(parents=True)
+            (output / "stale").write_text("remove", encoding="utf-8")
+
+            with mock.patch.dict(
+                versioning.os.environ,
+                {"RUNNER_TEMP": str(runner_temp)},
+            ):
+                self.assertEqual(
+                    versioning.prepare_output_directory(output, "fixture"),
+                    output.resolve(),
+                )
+
+            self.assertFalse(output.exists())
+
     def test_output_cleanup_rejects_registered_sibling_worktree(self) -> None:
         with tempfile.TemporaryDirectory() as temp_name:
             sibling = Path(temp_name) / "registered-sibling"
diff --git a/scripts/versioning.py b/scripts/versioning.py
index dade4b69b..777e5ae50 100644
--- a/scripts/versioning.py
+++ b/scripts/versioning.py
@@ -349,12 +349,11 @@ def prepare_output_directory(path: pathlib.Path, label: 
str) -> pathlib.Path:
     }
     runner_temp = os.environ.get("RUNNER_TEMP")
     if runner_temp:
-        runner_temp_root = pathlib.Path(runner_temp).expanduser()
-        if runner_temp_root.is_symlink():
-            fail(
-                "RUNNER_TEMP must not be a symbolic link: "
-                f"{runner_temp_root}"
-            )
+        runner_temp_root = require_no_symlinked_output_components(
+            pathlib.Path(runner_temp).expanduser(),
+            "RUNNER_TEMP",
+            controlled_roots,
+        )
         controlled_roots.add(runner_temp_root)
     raw_absolute = require_no_symlinked_output_components(
         raw, label, controlled_roots

Reply via email to