Skip to content

Commit 98bd684

Browse files
committed
Add integration test
1 parent aee9345 commit 98bd684

7 files changed

Lines changed: 170 additions & 0 deletions

File tree

MODULE.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ use_repo(
243243
"rules_python_runtime_env_tc_info",
244244
"somepkg_with_build_files",
245245
"whl_library_extras_direct_dep",
246+
"whl_perms_bad_perms_pkg",
246247
"whl_with_build_files",
247248
)
248249

python/private/internal_dev_deps.bzl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,14 @@ def _internal_dev_deps_impl(mctx):
109109
config_load = "@rules_python//tests/pypi/whl_library/testdata:packages.bzl",
110110
)
111111

112+
# Setup for //tests/pypi/whl_permissions
113+
# Test that wheels with bad file permissions can be extracted
114+
whl_library(
115+
name = "whl_perms_bad_perms_pkg",
116+
whl_file = "//tests/pypi/whl_permissions:bad_perms_pkg-1.0-py3-none-any.whl",
117+
requirement = "bad-perms-pkg==1.0",
118+
)
119+
112120
def _whl_library_from_dir(*, name, output, root, **kwargs):
113121
whl_from_dir_repo(
114122
name = "{}_whl".format(name),
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
load("//python:defs.bzl", "py_binary")
2+
load("//python:py_test.bzl", "py_test")
3+
load("//tests/support:support.bzl", "SUPPORTS_BZLMOD_UNIXY")
4+
5+
# Tool to generate test wheels with bad permissions
6+
py_binary(
7+
name = "build_test_wheel",
8+
srcs = ["build_test_wheel.py"],
9+
)
10+
11+
# Pre-built test wheel with files that have no read permissions.
12+
# This wheel is created by build_test_wheel.py and checked into the repo.
13+
# The files inside have mode 000 (no permissions), which tests that
14+
# whl_extract.bzl correctly fixes permissions after extraction.
15+
exports_files(["bad_perms_pkg-1.0-py3-none-any.whl"])
16+
17+
# Test that we can use a wheel with bad file permissions
18+
py_test(
19+
name = "whl_permissions_test",
20+
srcs = ["whl_permissions_test.py"],
21+
target_compatible_with = SUPPORTS_BZLMOD_UNIXY,
22+
deps = [
23+
"@whl_perms_bad_perms_pkg//:pkg",
24+
],
25+
)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Wheel Permissions Test
2+
3+
This test verifies that `rules_python` can correctly handle Python wheels that contain files without read permissions.
4+
5+
## Background
6+
7+
Some wheels are created with files that have incorrect permissions (e.g., mode `000`). When these wheels are extracted by Bazel's `rctx.extract()`, the file permissions are preserved from the zip file. This causes failures when subsequent operations try to read these files, such as:
8+
9+
- Reading `__init__.py` files during namespace package detection
10+
- Reading metadata files
11+
- Importing Python modules
12+
13+
## Test Setup
14+
15+
### Files
16+
17+
- **`bad_perms_pkg-1.0-py3-none-any.whl`**: A pre-built test wheel with files that have mode `000` (no permissions)
18+
- **`build_test_wheel.py`**: Script used to generate the test wheel (for reference/regeneration)
19+
- **`whl_permissions_test.py`**: Integration test that verifies the wheel can be extracted and used
20+
21+
## Regenerating the Test Wheel
22+
23+
If you need to regenerate the test wheel:
24+
25+
```bash
26+
bazel run //tests/pypi/whl_permissions:build_test_wheel -- \
27+
$(pwd)/tests/pypi/whl_permissions/bad_perms_pkg-1.0-py3-none-any.whl
28+
```
29+
30+
Verify the permissions are set correctly:
31+
```bash
32+
zipinfo -l tests/pypi/whl_permissions/bad_perms_pkg-1.0-py3-none-any.whl
33+
```
34+
35+
You should see entries like:
36+
```
37+
?rw------- 2.0 unx bad_perms_pkg/__init__.py
38+
?rw------- 2.0 unx bad_perms_pkg-1.0.dist-info/METADATA
39+
```
40+
41+
The `?rw-------` indicates mode `000` for those files.
1.1 KB
Binary file not shown.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env python3
2+
"""Build a test wheel with files that have no read permissions.
3+
4+
This simulates wheels that are created with incorrect file permissions,
5+
which can cause extraction failures when Bazel tries to read the files.
6+
"""
7+
8+
import sys
9+
import zipfile
10+
from pathlib import Path
11+
12+
13+
def create_bad_perms_wheel(output_path: str):
14+
"""Create a wheel file with files that have no read permissions."""
15+
with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as whl:
16+
# Add __init__.py with no read permissions (mode 000)
17+
info = zipfile.ZipInfo('bad_perms_pkg/__init__.py')
18+
info.external_attr = 0o000 << 16 # No permissions
19+
whl.writestr(info, 'def test():\n return "hello"\n')
20+
21+
# Add a module file with no read permissions
22+
module_info = zipfile.ZipInfo('bad_perms_pkg/module.py')
23+
module_info.external_attr = 0o000 << 16 # No permissions
24+
whl.writestr(module_info, 'VALUE = 42\n')
25+
26+
# Add METADATA with no read permissions
27+
metadata = zipfile.ZipInfo('bad_perms_pkg-1.0.dist-info/METADATA')
28+
metadata.external_attr = 0o000 << 16 # No permissions
29+
whl.writestr(metadata, '''Metadata-Version: 2.1
30+
Name: bad-perms-pkg
31+
Version: 1.0
32+
Summary: Test package with bad file permissions
33+
Author: Test
34+
License: Apache-2.0
35+
''')
36+
37+
# Add WHEEL with normal permissions (so the wheel can be opened)
38+
wheel_info = zipfile.ZipInfo('bad_perms_pkg-1.0.dist-info/WHEEL')
39+
wheel_info.external_attr = 0o644 << 16
40+
whl.writestr(wheel_info, '''Wheel-Version: 1.0
41+
Generator: test
42+
Root-Is-Purelib: true
43+
Tag: py3-none-any
44+
''')
45+
46+
# Add RECORD with normal permissions
47+
record = zipfile.ZipInfo('bad_perms_pkg-1.0.dist-info/RECORD')
48+
record.external_attr = 0o644 << 16
49+
whl.writestr(record, '''bad_perms_pkg/__init__.py,,
50+
bad_perms_pkg/module.py,,
51+
bad_perms_pkg-1.0.dist-info/METADATA,,
52+
bad_perms_pkg-1.0.dist-info/WHEEL,,
53+
bad_perms_pkg-1.0.dist-info/RECORD,,
54+
''')
55+
56+
57+
if __name__ == '__main__':
58+
if len(sys.argv) != 2:
59+
print(f"Usage: {sys.argv[0]} <output_wheel_path>", file=sys.stderr)
60+
sys.exit(1)
61+
62+
output_path = sys.argv[1]
63+
create_bad_perms_wheel(output_path)
64+
print(f"Created wheel with bad permissions: {output_path}")
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""Test that wheels with incorrect file permissions can be extracted and used.
2+
3+
Some wheels have files without read permissions set, which causes errors
4+
when Bazel tries to read them during extraction. This test verifies that
5+
the permission-fixing logic in whl_extract.bzl handles these cases correctly.
6+
"""
7+
8+
import unittest
9+
10+
11+
class WhlPermissionsTest(unittest.TestCase):
12+
def test_can_import_from_bad_perms_wheel(self):
13+
"""Test that we can import and use code from a wheel with bad permissions."""
14+
# If the permissions weren't fixed, the whl_library rule would have
15+
# failed when trying to read __init__.py during namespace package detection.
16+
import bad_perms_pkg
17+
18+
# Verify we can call functions from the module
19+
result = bad_perms_pkg.test()
20+
self.assertEqual(result, "hello")
21+
22+
def test_can_import_module_from_bad_perms_wheel(self):
23+
"""Test that we can import submodules from a wheel with bad permissions."""
24+
from bad_perms_pkg import module
25+
26+
# Verify we can access module contents
27+
self.assertEqual(module.VALUE, 42)
28+
29+
30+
if __name__ == '__main__':
31+
unittest.main()

0 commit comments

Comments
 (0)