US08-02: Build a Reproducible Application Image (#97)
This commit was merged in pull request #97.
This commit is contained in:
72
docker/fetch-immich-go.py
Normal file
72
docker/fetch-immich-go.py
Normal file
@@ -0,0 +1,72 @@
|
||||
"""Download one pinned immich-go release and verify it before unpacking (US08-02).
|
||||
|
||||
Run at image build time by the `uploader` stage, with the interpreter that is already
|
||||
in the base image: no curl, no wget, and no download tooling in the layer that ships.
|
||||
The checksum is not advisory — a release asset that does not match the pinned digest
|
||||
is a failed build, not a warning, because the uploader's flags and report format are
|
||||
what the upload parser is written against (concept §15).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import platform
|
||||
import tarfile
|
||||
import tempfile
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
RELEASE_URL = "https://github.com/simulot/immich-go/releases/download/v{version}/{asset}"
|
||||
# Debian/BuildKit architecture as the interpreter sees it → release asset name.
|
||||
ASSETS = {
|
||||
"x86_64": ("immich-go_Linux_x86_64.tar.gz", "amd64"),
|
||||
"amd64": ("immich-go_Linux_x86_64.tar.gz", "amd64"),
|
||||
"aarch64": ("immich-go_Linux_arm64.tar.gz", "arm64"),
|
||||
"arm64": ("immich-go_Linux_arm64.tar.gz", "arm64"),
|
||||
}
|
||||
TIMEOUT_SECONDS = 300
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--version", required=True, help="immich-go release, without the v")
|
||||
parser.add_argument("--sha256-amd64", required=True)
|
||||
parser.add_argument("--sha256-arm64", required=True)
|
||||
parser.add_argument("--into", default="/usr/local/bin")
|
||||
args = parser.parse_args()
|
||||
|
||||
machine = platform.machine().lower()
|
||||
if machine not in ASSETS:
|
||||
raise SystemExit(f"unsupported architecture: {machine}")
|
||||
asset, arch = ASSETS[machine]
|
||||
expected = {"amd64": args.sha256_amd64, "arm64": args.sha256_arm64}[arch]
|
||||
url = RELEASE_URL.format(version=args.version, asset=asset)
|
||||
|
||||
with urllib.request.urlopen(url, timeout=TIMEOUT_SECONDS) as response: # noqa: S310
|
||||
payload = response.read()
|
||||
digest = hashlib.sha256(payload).hexdigest()
|
||||
if digest != expected:
|
||||
raise SystemExit(f"checksum mismatch for {url}: {digest} != {expected}")
|
||||
|
||||
target = Path(args.into)
|
||||
target.mkdir(parents=True, exist_ok=True)
|
||||
with tempfile.TemporaryDirectory() as work:
|
||||
archive = Path(work) / asset
|
||||
archive.write_bytes(payload)
|
||||
with tarfile.open(archive) as tar:
|
||||
member = tar.getmember("immich-go")
|
||||
# Extract exactly the one file this pin is about, by name, so nothing
|
||||
# else in the archive can decide where it lands.
|
||||
extracted = tar.extractfile(member)
|
||||
if extracted is None:
|
||||
raise SystemExit("release archive contains no immich-go binary")
|
||||
binary = target / "immich-go"
|
||||
binary.write_bytes(extracted.read())
|
||||
binary.chmod(0o755)
|
||||
print(f"immich-go {args.version} ({arch}) verified {digest}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user