1
0
mirror of https://github.com/veracrypt/VeraCrypt.git synced 2026-06-17 01:56:10 -05:00

Linux: Support legacy Python for reproducible build

Allow reproducible makeself finalization to run with Python 2.6+ or Python 3 by avoiding Python 3-only syntax and probing python3, python, then python2.
This commit is contained in:
Mounir IDRASSI
2026-06-09 18:28:25 +09:00
parent dd96f1a483
commit 3575194415
2 changed files with 16 additions and 14 deletions
+11 -10
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python
#
# Copyright (c) 2026 VeraCrypt
# Governed by the Apache License 2.0.
@@ -14,6 +14,8 @@
# CRCsum makes its extractor skip the redundant CRC check.
# - MD5 is recomputed, which the extractor still verifies.
#
# Compatible with Python >= 2.6 and Python 3.
#
# Usage: makeself_repro_finalize.py <archive>
import hashlib
@@ -23,28 +25,27 @@ import sys
def finalize(path):
with open(path, "rb") as f:
raw = bytearray(f.read())
text = raw.decode("latin1", errors="replace")
raw = f.read()
text = raw.decode("latin1")
# Locate payload start by line count, mirroring makeself's own extractor.
m = re.search(r'^skip="(\d+)"', text, re.MULTILINE)
if not m:
sys.exit(f"{path}: no skip= line in makeself header")
sys.exit("%s: no skip= line in makeself header" % path)
skip = int(m.group(1))
header_text = "\n".join(text.split("\n")[:skip]) + "\n"
offset = len(header_text.encode("latin1"))
if bytes(raw[offset:offset + 3]) != b"\x1f\x8b\x08":
sys.exit(f"{path}: no gzip magic at payload offset {offset}")
if raw[offset:offset + 3] != b"\x1f\x8b\x08":
sys.exit("%s: no gzip magic at payload offset %d" % (path, offset))
# gzip header mtime: 4-byte LE uint at offset+4 (RFC 1952 section 2.3.1).
raw[offset + 4:offset + 8] = b"\x00\x00\x00\x00"
payload = bytes(raw[offset:])
payload = raw[offset:offset + 4] + b"\x00\x00\x00\x00" + raw[offset + 8:]
new_md5 = hashlib.md5(payload).hexdigest()
# CRCsum -> all zeros (extractor then skips the CRC check); MD5 -> fresh.
new_header = re.sub(r'CRCsum="[^"]*"', 'CRCsum="0000000000"', header_text)
new_header = re.sub(r'MD5="[0-9a-fA-F]+"', f'MD5="{new_md5}"', new_header)
new_header = re.sub(r'MD5="[0-9a-fA-F]+"', 'MD5="%s"' % new_md5, new_header)
new_bytes = new_header.encode("latin1")
# Line count must stay the same so makeself's "skip=" remains accurate.
if new_bytes.count(b"\n") != skip:
sys.exit(f"{path}: header line count changed during rewrite")
sys.exit("%s: header line count changed during rewrite" % path)
with open(path, "wb") as f:
f.write(new_bytes + payload)
+5 -4
View File
@@ -319,6 +319,7 @@ TAR_DETERMINISTIC := $(strip $(shell t=$$(mktemp 2>/dev/null) && tar --sor
GZIP_NO_TIMESTAMP := $(strip $(shell printf x | gzip -n -c >/dev/null 2>&1 && echo yes))
MAKESELF_PACKAGING_DATE := $(strip $(shell makeself --help 2>&1 | grep -q -- '--packaging-date' && echo yes))
MAKESELF_TAR_EXTRA := $(strip $(shell makeself --help 2>&1 | grep -q -- '--tar-extra' && echo yes))
PYTHON_REPRO_FINALIZE := $(strip $(shell for p in python3 python python2; do command -v $$p >/dev/null 2>&1 || continue; $$p -c 'import sys; v=sys.version_info; sys.exit(not (v[0] > 2 or (v[0] == 2 and v[1] >= 6)))' >/dev/null 2>&1 && command -v $$p && break; done))
INSTALL_UNINSTALLER ?= 1
INSTALL_LICENSE ?= 1
@@ -631,11 +632,11 @@ endif
# makeself runs 'gzip -c9 < tmpfile' which writes tmpfile's mtime into
# the gzip header (SOURCE_DATE_EPOCH is ignored for redirected stdin).
# Zero the mtime and refresh CRCsum/MD5; installer --check still passes.
@if command -v python3 >/dev/null 2>&1; then \
python3 $(BASE_DIR)/Build/Tools/makeself_repro_finalize.py \
$(BASE_DIR)/Setup/Linux/$(INSTALLER_NAME); \
@if [ -n "$(PYTHON_REPRO_FINALIZE)" ]; then \
"$(PYTHON_REPRO_FINALIZE)" "$(BASE_DIR)/Build/Tools/makeself_repro_finalize.py" \
"$(BASE_DIR)/Setup/Linux/$(INSTALLER_NAME)"; \
else \
echo "Reproducible build: python3 unavailable, skipping makeself finalize"; \
echo "Reproducible build: Python 2.6+ unavailable, skipping makeself finalize"; \
fi
appimage: prepare