Skip to content

fix(install): follow Windows runfiles junctions when copying files - #1076

Merged
aiuto merged 2 commits into
bazelbuild:mainfrom
JSGette:jsgette/pkg-install-windows-junctions
Oct 1, 2026
Merged

aiuto merged 2 commits into
bazelbuild:mainfrom
JSGette:jsgette/pkg-install-windows-junctions

Conversation

@JSGette

@JSGette JSGette commented Aug 13, 2026 •

Copy link
Copy Markdown
Contributor

pkg_install fails on Windows when --enable_runfiles is set. Bazel materializes file runfiles as directory junctions, but junctions cannot point at files, so shutil.copyfile or open() raises PermissionError: [Errno 13] Permission denied.

os.path.realpath() resolves full path following symlinks, so that is essentially a no-op on Unix (extra stat() call) but resolves junctions on Windows

gh-worker-dd-mergequeue-cf854d Bot pushed a commit to DataDog/datadog-agent that referenced this pull request Aug 17, 2026
<!--Please give us some feedback on your experience writing this PR ! https://app.datadoghq.com/forms/43db4c02-6837-400c-8083-692e141b1b88 !-->

### What does this PR do?

As described in bazelbuild/rules_pkg#1076, Bazel creates a junction on files that is wrong as they are only supposed to be used with directories. This leads to permission errors:
```python
PermissionError: [Errno 13] Permission denied
```

Co-authored-by: joseph.gette <joseph.gette@datadoghq.com>
@aiuto

aiuto commented Sep 30, 2026

Copy link
Copy Markdown
Collaborator

Can you rebase and push so tests run without the broken setup.

--enable_runfiles on Windows creates directory junctions for file runfiles.
Junctions cannot point at files, so shutil.copyfile fails with Permission denied.
Resolve the reparse point before copying.
Suggested by @alopezz: realpath resolves reparse points on Windows
and symlinks on Unix, removing the need for sys.platform conditional
and os.readlink try/except.
@JSGette
JSGette force-pushed the jsgette/pkg-install-windows-junctions branch from 2bd3f8c to e5e3b7c Compare October 1, 2026 08:04
@JSGette
JSGette marked this pull request as ready for review October 1, 2026 08:05
@JSGette
JSGette requested review from aiuto and cgrindel as code owners October 1, 2026 08:05
@aiuto
aiuto merged commit 1b2295d into bazelbuild:main Oct 1, 2026
6 checks passed
onnosteenbergen-samotics added a commit to onnosteenbergen-samotics/rules_pkg that referenced this pull request Oct 7, 2026
Since rules_python 1.9, py_binary/py_test default to --enable_runfiles
on Windows. Bazel may then create a directory junction for a file
runfile, which cannot be opened or executed ("Permission denied").
Raising the minimum rules_python to 2.3.0 exposed this in our Windows
tests and in verify_archive_test.

Resolve runfiles paths with os.path.realpath before opening them, as
was done for pkg_install in bazelbuild#1076.
onnosteenbergen-samotics added a commit to onnosteenbergen-samotics/rules_pkg that referenced this pull request Oct 7, 2026
Since rules_python 1.9, py_binary/py_test default to --enable_runfiles
on Windows. Bazel may then create a directory junction for a file
runfile, which can not be opened or executed ("Permission denied").
Raising the minimum rules_python to 2.3.0 exposed this in our Windows
tests and in verify_archive_test.

os.path.realpath does not help: on Windows it fails on such a junction
with WinError 267. Read the junction target with os.readlink instead,
in verify_archive_test, in pkg_install (replacing the realpath from
bazelbuild#1076) and, through //tests/util:runfiles_util, in the tests.
onnosteenbergen-samotics added a commit to onnosteenbergen-samotics/rules_pkg that referenced this pull request Oct 7, 2026
Since rules_python 1.9, py_binary/py_test default to --enable_runfiles
on Windows. Bazel may then create a directory junction for a file
runfile, which can not be opened or executed ("Permission denied").
Raising the minimum rules_python to 2.3.0 exposed this in our Windows
tests and in verify_archive_test.

os.path.realpath does not help: on Windows it fails on such a junction
with WinError 267. Read the junction target with os.readlink instead,
in verify_archive_test, in pkg_install (replacing the realpath from
bazelbuild#1076) and, through //tests/util:runfiles_util, in the tests.
onnosteenbergen-samotics added a commit to onnosteenbergen-samotics/rules_pkg that referenced this pull request Oct 7, 2026
Since rules_python 1.9, py_binary/py_test default to --enable_runfiles
on Windows. Bazel may then create a directory junction for a file
runfile, which can not be opened or executed ("Permission denied").
Raising the minimum rules_python to 2.3.0 exposed this in our Windows
tests and in verify_archive_test.

os.path.realpath does not help: on Windows it fails on such a junction
with WinError 267. Read the junction target with os.readlink instead,
in verify_archive_test, in pkg_install (replacing the realpath from
bazelbuild#1076) and, through //tests/util:runfiles_util, in the tests.
rdesgroppes added a commit to DataDog/datadog-agent that referenced this pull request Oct 8, 2026
### What does this PR do?
Bump `rules_pkg` to 1.3.0 and repin its `archive_override` to upstream
main at bazelbuild/rules_pkg#1076, which upstreams the local Windows
junction patch.
Apply the pending bazelbuild/rules_pkg#1084 on top as the only patch.

### Motivation
RPM 4.20 redefined `%{_builddir}` as a per-package build directory
(rpm-software-management/rpm#2885), which breaks the relative paths
`rules_pkg` generates for `%install` and `%files`.
With RPM 6.0.1, as shipped by Ubuntu 26.04 LTS, `bazel build
//packages/dogstatsd:rpm` fails with `Could not open %files file` and
`//packages/installer/linux:rpm` with `cp: cannot stat
...README_rpm.md`.
CI images ship RPM 4.18.2 and older, so they are not affected yet, but
running them against the patch proves it keeps working with older RPM
versions, which upstream cannot test.

### Describe how you validated your changes
Both targets above build with RPM 6.0.1, whereas they fail without this
change once `MakeRpm` actions bypass caches
(`--modify_execution_info=MakeRpm=+no-cache`).

### Additional Notes
`rpmbuild` is a system toolchain absent from action keys, so cached RPMs
mask both the breakage and the fix.
rdesgroppes added a commit to DataDog/datadog-agent that referenced this pull request Oct 8, 2026
### What does this PR do?
Bump `rules_pkg` to 1.3.0 and repin its `archive_override` to upstream
main at bazelbuild/rules_pkg#1076, which upstreams the local Windows
junction patch.
Apply the pending bazelbuild/rules_pkg#1084 on top as the only patch.

### Motivation
RPM 4.20 redefined `%{_builddir}` as a per-package build directory
(rpm-software-management/rpm#2885), which breaks the relative paths
`rules_pkg` generates for `%install` and `%files`.
With RPM 6.0.1, as shipped by Ubuntu 26.04 LTS, `bazel build
//packages/dogstatsd:rpm` fails with `Could not open %files file` and
`//packages/installer/linux:rpm` with `cp: cannot stat
...README_rpm.md`.
CI images ship RPM 4.18.2 and older, so they are not affected yet, but
running them against the patch proves it keeps working with older RPM
versions, which upstream cannot test.

### Describe how you validated your changes
Both targets above build with RPM 6.0.1, whereas they fail without this
change once `MakeRpm` actions bypass caches
(`--modify_execution_info=MakeRpm=+no-cache`).

### Additional Notes
The `rpmbuild` version only reaches `MakeRpm` action keys through
`--debuginfo_type`, which no target enables, so cached RPMs mask both
the breakage and the fix.
gh-worker-dd-mergequeue-cf854d Bot pushed a commit to DataDog/datadog-agent that referenced this pull request Oct 8, 2026
…57825)

### What does this PR do?
Bump `rules_pkg` to 1.3.0 and repin its `archive_override` to upstream main at bazelbuild/rules_pkg#1076, which upstreams the local Windows junction patch.

Conversely, apply the pending bazelbuild/rules_pkg#1084 on top as the only patch.

### Motivation
RPM 4.20 redefined `%{_builddir}` as a per-package build directory (rpm-software-management/rpm#2885), which breaks the relative paths `rules_pkg` generates for `%install` and `%files`.

With RPM 6.0.1, as shipped by Ubuntu 26.04 LTS (author's laptop), `bazel build //packages/dogstatsd:rpm` fails with `Could not open %files file` and `//packages/installer/linux:rpm` with `cp: cannot stat ...README_rpm.md`.

CI images ship RPM 4.18.2 and older, so they are not affected yet, but running them against the patch proves it keeps working with older RPM versions, which upstream doesn't necessarily cover.

### Describe how you validated your changes
Both targets above build with RPM 6.0.1, whereas they fail without this change once `MakeRpm` actions bypass caches
(`--modify_execution_info=MakeRpm=+no-cache`).

### Additional Notes
The `rpmbuild` version only reaches `MakeRpm` action keys through `--debuginfo_type`, which no target enables, so cached RPMs might mask both the breakage and the fix when switching the base build image to Ubuntu 26.04.
This dormant issue predates bazelbuild/rules_pkg#1084, and therefore deserves a separate upstream contribution.

Co-authored-by: regis.desgroppes <regis.desgroppes@datadoghq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants