@@ -3598,6 +3598,123 @@ EOF
35983598 [[ -f " $output_base /external/+repo+foo/ruff" ]] || fail " Expected ruff binary to be extracted"
35993599}
36003600
3601+ # Verifies that files without user-readable permissions in archives are made
3602+ # readable after extraction.
3603+ function test_extract_non_readable_file_tar() {
3604+ local archive_tar=" ${TEST_TMPDIR} /non_readable.tar.gz"
3605+
3606+ python3 -c "
3607+ import tarfile
3608+ import io
3609+ import gzip
3610+
3611+ content = b'secret content'
3612+ with gzip.open('${archive_tar} ', 'wb') as gz:
3613+ with tarfile.open(fileobj=gz, mode='w') as tar:
3614+ info = tarfile.TarInfo(name='non_readable_dir/non_readable.txt')
3615+ info.size = len(content)
3616+ info.mode = 0o000 # No permissions
3617+ tar.addfile(info, io.BytesIO(content))
3618+ "
3619+
3620+ cat > $( setup_module_dot_bazel) << EOF
3621+ repo = use_repo_rule('//:test.bzl', 'repo')
3622+ repo(name = 'foo')
3623+ EOF
3624+ touch BUILD
3625+
3626+ cat > test.bzl << EOF
3627+ def _impl(repository_ctx):
3628+ repository_ctx.extract('${archive_tar} ', 'out_dir')
3629+ # Verify the file is readable by reading it
3630+ content = repository_ctx.read('out_dir/non_readable_dir/non_readable.txt')
3631+ if 'secret content' not in content:
3632+ fail('Expected to read file content, got: ' + content)
3633+ repository_ctx.file("BUILD", "filegroup(name='bar', srcs=[])")
3634+
3635+ repo = repository_rule(implementation=_impl)
3636+ EOF
3637+
3638+ bazel build @foo//:bar >& $TEST_log || fail " Failed to build"
3639+ }
3640+
3641+ function test_extract_non_readable_file_zip() {
3642+ local archive_zip=" ${TEST_TMPDIR} /non_readable.zip"
3643+
3644+ pushd " ${TEST_TMPDIR} "
3645+ mkdir -p non_readable_zip_dir
3646+ echo " secret zip content" > non_readable_zip_dir/non_readable.txt
3647+ python3 -c "
3648+ import zipfile
3649+ with zipfile.ZipFile('non_readable.zip', 'w') as zf:
3650+ info = zipfile.ZipInfo('non_readable_zip_dir/non_readable.txt')
3651+ # S_IFREG (0o100000) marks it as a regular file, but with no permission bits.
3652+ # This ensures getPermissions() returns the actual mode rather than defaulting to 0755.
3653+ info.external_attr = 0o100000 << 16
3654+ zf.writestr(info, 'secret zip content')
3655+ "
3656+ popd
3657+
3658+ cat > $( setup_module_dot_bazel) << EOF
3659+ repo = use_repo_rule('//:test.bzl', 'repo')
3660+ repo(name = 'foo')
3661+ EOF
3662+ touch BUILD
3663+
3664+ cat > test.bzl << EOF
3665+ def _impl(repository_ctx):
3666+ repository_ctx.extract('${archive_zip} ', 'out_dir')
3667+ # Verify the file is readable by reading it
3668+ content = repository_ctx.read('out_dir/non_readable_zip_dir/non_readable.txt')
3669+ if 'secret zip content' not in content:
3670+ fail('Expected to read file content, got: ' + content)
3671+ repository_ctx.file("BUILD", "filegroup(name='bar', srcs=[])")
3672+
3673+ repo = repository_rule(implementation=_impl)
3674+ EOF
3675+
3676+ bazel build @foo//:bar >& $TEST_log || fail " Failed to build"
3677+ }
3678+
3679+ function test_extract_non_readable_file_ar() {
3680+ local archive_ar=" ${TEST_TMPDIR} /non_readable.ar"
3681+
3682+ # Create a valid AR file, then patch the permission field to 0000
3683+ pushd " ${TEST_TMPDIR} "
3684+ echo " secret ar content" > non_readable.txt
3685+ ar rc non_readable.ar non_readable.txt
3686+ # Patch the mode field (bytes 40-47 after the 8-byte magic) to "0 "
3687+ python3 -c "
3688+ with open('non_readable.ar', 'r+b') as f:
3689+ # AR magic is 8 bytes, then header starts
3690+ # Header format: filename(16) + mtime(12) + owner(6) + group(6) + mode(8) + size(10) + magic(2)
3691+ # Mode is at offset 8 + 16 + 12 + 6 + 6 = 48
3692+ f.seek(48)
3693+ f.write(b'0 ') # 8 bytes for mode 0000 in octal
3694+ "
3695+ popd
3696+
3697+ cat > $( setup_module_dot_bazel) << EOF
3698+ repo = use_repo_rule('//:test.bzl', 'repo')
3699+ repo(name = 'foo')
3700+ EOF
3701+ touch BUILD
3702+
3703+ cat > test.bzl << EOF
3704+ def _impl(repository_ctx):
3705+ repository_ctx.extract('${archive_ar} ', 'out_dir')
3706+ # Verify the file is readable by reading it
3707+ content = repository_ctx.read('out_dir/non_readable.txt')
3708+ if 'secret ar content' not in content:
3709+ fail('Expected to read file content, got: ' + content)
3710+ repository_ctx.file("BUILD", "filegroup(name='bar', srcs=[])")
3711+
3712+ repo = repository_rule(implementation=_impl)
3713+ EOF
3714+
3715+ bazel build @foo//:bar >& $TEST_log || fail " Failed to build"
3716+ }
3717+
36013718# Regression test for https://github.com/bazelbuild/bazel/issues/27446.
36023719function do_test_local_module_file_patch() {
36033720 cat > $( setup_module_dot_bazel) << 'EOF '
0 commit comments