You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
support ZIP files with zeroed out fields (e.g. for reproducible builds) #87713
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee=Noneclosed_at=Nonecreated_at=<Date2021-03-18.21:25:38.236>labels= ['type-feature', 'library', '3.10']
title='support ZIP files with zeroed out fields (e.g. for reproducible builds)'updated_at=<Date2021-06-22.13:49:25.963>user='https://github.com/eighthave'
It is now standard for Java JARs and Android APKs (both ZIP files) to zero out lots of the fields in the ZIP header. For example:
each file entry has the date set to zero
the create_system is always set to zero on all platforms
zipfile currently cannot create such ZIPs because of two small restrictions that it introduced:
must use a tuple of 6 values to set the date
forced create_system value based on sys.platform == 'win32'
maybe other fields?
I lump these together because it might make sense to handle this with a single argument, something like zero_header=True. The use case is for working with ZIP, JAR, APK, AAR files for reproducible builds. The whole build system for F-Droid is built in Python. We need to be able to copy the JAR/APK signatures in order to reproduce signed builds using only the source code and the signature files themselves. Right now, that's not possible because building a ZIP with Python's zipfile cannot zero out the ZIP header like other tools can, including Java.
I just found another specific example in _open_to_write(). 0 is a valid value for zinfo.external_attr. But this code always forces 0 to something else:
external_attr == 0 may cause issues with permissions.
That may be true in some scenarios, but not being able to set it to 0 means you can't create identical files to those produced by other tools -- like those used to generate APKs -- which do in fact set it to 0.
I think it makes also sense to replace hard-coded ZipInfo class with dispatcher attribute on the class:
@@ -1203,6 +1211,7 @@ class ZipFile:
fp = None # Set here since __del__ checks it
_windows_illegal_name_trans_table = None
+ zipinfo_class = ZipInfo
def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=True,
compresslevel=None, *, strict_timestamps=True):
@@ -1362,7 +1371,7 @@ def _RealGetContents(self):
# Historical ZIP filename encoding
filename = filename.decode('cp437')
# Create ZipInfo instance to store file information
- x = ZipInfo(filename)+ x = self.zipinfo_class(filename)
obfusk commented on Mar 23, 2021
obfuskmannequin
Mannequin
More actions
The __getattr__ hack is not needed. You can reset the flags in a different, more straight forward way
As mentioned, ZipFile._open_to_write() will modify the ZipInfo's .external_attr when it is set to 0.
I just found another specific example in _open_to_write(). 0 is a valid value for zinfo.external_attr. But this code always forces 0 to something else:
if not zinfo.external_attr:
zinfo.external_attr = 0o600 \<\< 16 # permissions: ?rw\-------
Your alternative doesn't seem to take that subsequent modification into account.
eighthave commented on Mar 24, 2021
eighthavemannequin
MannequinAuthor
More actions
For full reproducible builds you may have to write files to zipfiles in a well-defined order.
That already works fine now, we've been doing that with Python for years. But that leaves it up to the implemented to do. I suppose zipfile could provide a method to sort entries, but that's out of scope for this issue IMHO.
show that there is still evidence of demand for this feature
ask the stdlib maintainers if there is still interest in this, and if the PyPI package (which was not yet discussed here, appears to be well-written and proven in production) provides more helpful prior art
Activity
eighthave commentedon Mar 18, 2021
It is now standard for Java JARs and Android APKs (both ZIP files) to zero out lots of the fields in the ZIP header. For example:
zipfile currently cannot create such ZIPs because of two small restrictions that it introduced:
I lump these together because it might make sense to handle this with a single argument, something like zero_header=True. The use case is for working with ZIP, JAR, APK, AAR files for reproducible builds. The whole build system for F-Droid is built in Python. We need to be able to copy the JAR/APK signatures in order to reproduce signed builds using only the source code and the signature files themselves. Right now, that's not possible because building a ZIP with Python's zipfile cannot zero out the ZIP header like other tools can, including Java.
eighthave commentedon Mar 18, 2021
I just found another specific example in _open_to_write(). 0 is a valid value for zinfo.external_attr. But this code always forces 0 to something else:
obfusk commentedon Mar 22, 2021
I've created a draft PR; RFC :)
Also:
31 remaining items
obfusk commentedon Mar 22, 2021
That may be true in some scenarios, but not being able to set it to 0 means you can't create identical files to those produced by other tools -- like those used to generate APKs -- which do in fact set it to 0.
tiran commentedon Mar 23, 2021
The __getattr__ hack is not needed. You can reset the flags in a different, more straight forward way:
I think it makes also sense to replace hard-coded ZipInfo class with dispatcher attribute on the class:
obfusk commentedon Mar 23, 2021
As mentioned, ZipFile._open_to_write() will modify the ZipInfo's .external_attr when it is set to 0.
Your alternative doesn't seem to take that subsequent modification into account.
eighthave commentedon Mar 24, 2021
That already works fine now, we've been doing that with Python for years. But that leaves it up to the implemented to do. I suppose zipfile could provide a method to sort entries, but that's out of scope for this issue IMHO.
obfusk commentedon Jun 22, 2021
https://github.com/obfusk/apksigcopier currently produces reproducible ZIP files identical to those produced by apksigner using this code:
ctcjab commentedon Sep 18, 2026
TIL https://pypi.org/project/repro-zipfile/ (and https://pypi.org/project/repro-tarfile/) by @jayqi, which led me to wonder whether this functionality belongs in stdlib
ZipFile, which in turn led me here. Looks like this issue has stalled, so posting this comment to