-
Notifications
You must be signed in to change notification settings - Fork 369
Windows: _get_cache_dir flakes on tmpdir 8.3 short names (PathTraversalError) #886
Copy link
Copy link
Closed
Labels
area/ci-cdGitHub workflows, merge queue, gh-aw integrations, release pipeline.GitHub workflows, merge queue, gh-aw integrations, release pipeline.area/testingTest infrastructure, fixtures, e2e harness, coverage.Test infrastructure, fixtures, e2e harness, coverage.good first issueMaintainer-supported newcomer task; check human scope approval, review contact and existing claims.Maintainer-supported newcomer task; check human scope approval, review contact and existing claims.status/acceptedHuman scope approval; verify the issue's approval record and review contact before work.Human scope approval; verify the issue's approval record and review contact before work.type/bugSomething does not work as documented.Something does not work as documented.
Milestone
Description
Activity
Metadata
Metadata
Assignees
Labels
area/ci-cdGitHub workflows, merge queue, gh-aw integrations, release pipeline.GitHub workflows, merge queue, gh-aw integrations, release pipeline.area/testingTest infrastructure, fixtures, e2e harness, coverage.Test infrastructure, fixtures, e2e harness, coverage.good first issueMaintainer-supported newcomer task; check human scope approval, review contact and existing claims.Maintainer-supported newcomer task; check human scope approval, review contact and existing claims.status/acceptedHuman scope approval; verify the issue's approval record and review contact before work.Human scope approval; verify the issue's approval record and review contact before work.type/bugSomething does not work as documented.Something does not work as documented.
Type
Projects
- StatusShow more project fieldsDone
Symptom
tests/unit/policy/test_cache_atomicity.py::TestCacheAtomicity::test_concurrent_writers_no_torn_filesfails intermittently on the Windows unit-test job inbuild-release.ymlwith:First observed in run 24861961730 (post-merge, commit
8665f4b4, PR #885). Linux + macOS jobs are unaffected.Root cause
In
src/apm_cli/policy/discovery.py::_get_cache_dir(introduced in #832), the path-security guard does:ensure_path_withinresolves the candidate path throughPath.resolve()(which on Windows expands 8.3 short names likeRUNNER~1to the long formrunneradminand follows symlinks), but theproject_rootargument is compared as-passed.When the test calls it with
tempfile.mkdtemp(), Windows returns the short-name form (C:\Users\RUNNER~1\...). The candidate resolves toC:\Users\runneradmin\...\apm_modules\.policy-cache, the project root staysC:\Users\RUNNER~1\..., the prefix check fails, andPathTraversalErroris raised.The test is concurrent (
ThreadPoolExecutor), which is why it manifests racily -- depending on which thread wins to resolve first / on the runner's filesystem state, sometimes one or more threads see the short-name path and trip the guard.Why now
The bug has been latent since #832 merged. It surfaces only when:
tempfile.mkdtemp()returns a path with a~1short-name component (depends on user profile name length on the specific runner image)._write_cache -> _get_cache_dirruns.Recent main runs that ran the same Windows job have been mostly green by luck.
Suggested fix
Resolve
project_rootonce at the top of_get_cache_dirbefore passing it toensure_path_within, so both sides are normalized:Optionally, the same defensive normalization belongs inside
ensure_path_withinitself insrc/apm_cli/utils/path_security.pyso future callers can't repeat the mistake -- but the local fix is sufficient to unblock the test.How to verify
Add a regression test that constructs a
project_rootwith an unresolved component (e.g. viatempfile.mkdtemp()on Windows, or a deliberately-symlinked tmp dir on POSIX) and asserts_get_cache_dirdoes not raise.Run the existing concurrent test under stress (
pytest --count=20 tests/unit/policy/test_cache_atomicity.pywithpytest-repeat) on Windows.Scope notes
src/apm_cli/policy/discovery.py::_get_cache_dir(and possiblypath_security.pyif going for the defensive fix).Refs
8665f4b4)src/apm_cli/utils/path_security.py::ensure_path_within