Skip to content

fix(bundler): order bundle members by canonical POSIX arcname (reproducible builds)#3658

Merged
mnriem merged 1 commit into
github:mainfrom
jawwad-ali:fix/bundler-packager-deterministic-order
Jul 23, 2026
Merged

fix(bundler): order bundle members by canonical POSIX arcname (reproducible builds)#3658
mnriem merged 1 commit into
github:mainfrom
jawwad-ali:fix/bundler-packager-deterministic-order

Conversation

@jawwad-ali

Copy link
Copy Markdown
Contributor

What

_collect_files returned sorted(collected) — i.e. pathlib.Path comparison order. That ordering is platform-dependent: on Windows PurePath compares case-folded with backslash separators, while on Linux/macOS it compares the case-preserving forward-slash string.

But the zip member names are the canonical POSIX arcnames (build_bundle: file_path.relative_to(bundle_dir).as_posix()), which are platform-independent. So member order was derived from a platform-dependent key while member names were canonical — the same bundle built on Windows vs Linux/macOS produced archives whose members were laid out in different order, i.e. not byte-for-byte identical across build hosts. That contradicts the packager's stated reproducible-build guarantee (fixed timestamps + canonical 0644/0755 modes; test_build_is_deterministic asserts "byte-for-byte reproducible").

Fix

Order by the same canonical POSIX-arcname key used to name the members:

return sorted(collected, key=lambda p: p.relative_to(bundle_dir).as_posix())

Tests

tests/unit/test_bundler_packager.py::test_member_order_is_platform_independent — builds a bundle with mixed-case sibling files and asserts archive.namelist() == sorted(archive.namelist()). Fails before the fix on Windows (Path order groups case differently: apple.txt sorts before Foo.txt); passes after. CI's windows-latest matrix exercises this. All existing packager tests (incl. test_build_is_deterministic) still pass. ruff clean.


AI-assisted: authored with Claude Code. Verified the arcname key matches build_bundle's naming, and confirmed fail-before on Windows / pass-after.

…ucible builds)

_collect_files returned sorted(collected), i.e. pathlib.Path order, which is
platform-dependent: on Windows PurePath compares case-folded with backslash
separators, whereas the zip member NAMES are the canonical POSIX arcnames
(build_bundle: file_path.relative_to(bundle_dir).as_posix()). So the same
bundle built on Windows vs Linux/macOS produced archives whose members were
laid out in different order — not byte-for-byte identical across build hosts,
contradicting the packager's reproducible-build guarantee (fixed timestamps +
canonical modes).

Order by the same canonical POSIX-arcname key used to name members, so member
order is host-independent.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Ensures bundle archives are byte-for-byte reproducible across operating systems.

Changes:

  • Sorts bundle files by canonical POSIX archive name.
  • Adds a mixed-case filename regression test for platform-independent ordering.
Show a summary per file
File Description
src/specify_cli/bundler/services/packager.py Uses canonical archive names as the member-ordering key.
tests/unit/test_bundler_packager.py Verifies archive members use canonical string ordering.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Medium

@mnriem
mnriem merged commit 370551e into github:main Jul 23, 2026
14 checks passed
@mnriem

mnriem commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Thank you!

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