Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/fromager/downloads.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import logging
import os
import pathlib
import stat
import tarfile
import tempfile
import typing
Expand Down Expand Up @@ -81,6 +82,14 @@ def _download_with_retry() -> pathlib.Path:
for chunk in r.iter_content(chunk_size=64 * 1024):
if chunk:
tmp.write(chunk)
# NamedTemporaryFile creates files with mode 0o600. Widen to
# 0o644 so external wheel servers (e.g. nginx) running as a
# different user can read the file. Using fchmod before
# close+rename avoids a window where the final path exists
# with overly restrictive permissions.
os.fchmod(
tmp.fileno(), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH
)
tmp.close()
# Atomic rename on the same filesystem
os.rename(temp_path, outfile)
Expand Down
12 changes: 12 additions & 0 deletions tests/test_downloads.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from __future__ import annotations

import io
import os
import pathlib
import stat
import tarfile
import typing
import zipfile
Expand Down Expand Up @@ -72,6 +74,16 @@ def test_download_url_creates_parent_dirs(
assert download_url(destination_dir=tmp_path / "a" / "b", url=_PKG_URL).exists()


def test_download_url_world_readable(
requests_mock: requests_mock.Mocker, tmp_path: pathlib.Path
) -> None:
"""Downloaded files must be readable by other users (e.g. nginx)."""
requests_mock.get(_PKG_URL, content=b"data")
result = download_url(destination_dir=tmp_path, url=_PKG_URL)
mode = stat.S_IMODE(os.stat(result).st_mode)
assert mode == 0o644, f"expected 0o644, got {oct(mode)}"


def test_download_url_cleans_up_on_failure(
requests_mock: requests_mock.Mocker, tmp_path: pathlib.Path
) -> None:
Expand Down
Loading