From 619e0db95aeab495d88069cfa6213f442d9edb20 Mon Sep 17 00:00:00 2001 From: mikonyaa <227049489+mikonyaa@users.noreply.github.com> Date: Thu, 16 Jul 2026 11:48:32 +0500 Subject: [PATCH 1/4] Keep Homebrew checksum in sync --- .github/workflows/ci.yml | 3 +++ Formula/resizelint.rb | 2 +- Scripts/release/test-source-archive.sh | 13 ++++++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26c12e9..7d6e02f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,6 +67,9 @@ jobs: - name: Test signing identity resolution run: Scripts/ci/test-signing-identity-resolution.sh + - name: Test source release archive + run: Scripts/release/test-source-archive.sh + - name: Validate machine contracts run: Scripts/ci/validate-machine-contracts.py diff --git a/Formula/resizelint.rb b/Formula/resizelint.rb index 1d576e4..7ae061c 100644 --- a/Formula/resizelint.rb +++ b/Formula/resizelint.rb @@ -2,7 +2,7 @@ class Resizelint < Formula desc "Static analysis for Swift apps that need to work in every window size" homepage "https://github.com/mikonyaa/ResizeLint" url "https://github.com/mikonyaa/ResizeLint/releases/download/1.0.0/ResizeLint-1.0.0-source.tar.gz" - sha256 "fea82e67b1c23fbfea201d7d326b553d98847bdfed8cf2164053f2e1be33fac1" + sha256 "521c121050d792e1cd6c6cdb23e98bfab62cb4b5685704453aa8d5698c074e38" license "MIT" depends_on "swift" => :build diff --git a/Scripts/release/test-source-archive.sh b/Scripts/release/test-source-archive.sh index e5c98f2..6d6ce2e 100755 --- a/Scripts/release/test-source-archive.sh +++ b/Scripts/release/test-source-archive.sh @@ -4,6 +4,7 @@ set -euo pipefail repository_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P) builder="$repository_root/Scripts/release/build-source-archive.sh" +formula="$repository_root/Formula/resizelint.rb" if [[ ! -x "$builder" ]]; then echo "Source archive builder is missing or not executable: $builder" >&2 @@ -23,6 +24,16 @@ if [[ "$first_hash" != "$second_hash" ]]; then exit 1 fi +formula_hash=$(awk '/^[[:space:]]*sha256 / { gsub(/"/, "", $2); print $2; exit }' "$formula") +if [[ -z "$formula_hash" ]]; then + echo "Homebrew formula does not declare a source archive checksum" >&2 + exit 1 +fi +if [[ "$formula_hash" != "$first_hash" ]]; then + echo "Homebrew formula checksum is $formula_hash; source archive checksum is $first_hash" >&2 + exit 1 +fi + listing="$temporary_root/listing.txt" tar -tzf "$first" > "$listing" grep -q '^ResizeLint-1.0.0/Package.swift$' "$listing" @@ -33,4 +44,4 @@ if grep -Eq '(^|/)Formula/|(^|/)\.build/|(^|/)\.git/' "$listing"; then exit 1 fi -echo "Source archive self-test passed: $first_hash" +echo "Source archive reproducibility and Homebrew checksum test passed: $first_hash" From 1f6c870c60ff53052eeff486ae11dd18cb328f00 Mon Sep 17 00:00:00 2001 From: mikonyaa <227049489+mikonyaa@users.noreply.github.com> Date: Thu, 16 Jul 2026 12:02:33 +0500 Subject: [PATCH 2/4] Make source archive portable across tar variants --- Formula/resizelint.rb | 2 +- Scripts/release/build-source-archive.sh | 23 +++++++++++-------- Scripts/release/test-source-archive.sh | 30 +++++++++++++++++++++++-- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/Formula/resizelint.rb b/Formula/resizelint.rb index 7ae061c..5fde076 100644 --- a/Formula/resizelint.rb +++ b/Formula/resizelint.rb @@ -2,7 +2,7 @@ class Resizelint < Formula desc "Static analysis for Swift apps that need to work in every window size" homepage "https://github.com/mikonyaa/ResizeLint" url "https://github.com/mikonyaa/ResizeLint/releases/download/1.0.0/ResizeLint-1.0.0-source.tar.gz" - sha256 "521c121050d792e1cd6c6cdb23e98bfab62cb4b5685704453aa8d5698c074e38" + sha256 "c4cf634af5b2717749e413a655b5147f19a80aa613282d02ce43a32cf92dd253" license "MIT" depends_on "swift" => :build diff --git a/Scripts/release/build-source-archive.sh b/Scripts/release/build-source-archive.sh index 62d1edf..81bcfc1 100755 --- a/Scripts/release/build-source-archive.sh +++ b/Scripts/release/build-source-archive.sh @@ -44,16 +44,21 @@ listing="$temporary_root/files.txt" ) uncompressed="$temporary_root/source.tar" +tar_options=( + --format=ustar + --uid 0 + --gid 0 + --uname root + --gname root + --no-acls + --no-xattrs +) +if tar --version 2>/dev/null | grep -q 'bsdtar'; then + tar_options+=(--no-fflags --no-mac-metadata) +fi + tar -cf "$uncompressed" \ - --format=ustar \ - --uid 0 \ - --gid 0 \ - --uname root \ - --gname root \ - --no-acls \ - --no-fflags \ - --no-mac-metadata \ - --no-xattrs \ + "${tar_options[@]}" \ -C "$staging" \ -T "$listing" diff --git a/Scripts/release/test-source-archive.sh b/Scripts/release/test-source-archive.sh index 6d6ce2e..e8b5f2d 100755 --- a/Scripts/release/test-source-archive.sh +++ b/Scripts/release/test-source-archive.sh @@ -14,8 +14,34 @@ fi temporary_root=$(mktemp -d "${TMPDIR:-/tmp}/resizelint-source-test.XXXXXX") trap 'rm -rf "$temporary_root"' EXIT -first=$($builder "$temporary_root/first" 1.0.0) -second=$($builder "$temporary_root/second" 1.0.0) +fake_bin="$temporary_root/bin" +mkdir -p "$fake_bin" +real_tar=$(command -v tar) +cat > "$fake_bin/tar" <<'EOF' +#!/usr/bin/env bash + +set -euo pipefail + +if [[ "${1:-}" == "--version" ]]; then + echo "tar (GNU tar) 1.34" + exit 0 +fi + +for argument in "$@"; do + case "$argument" in + --no-fflags|--no-mac-metadata) + echo "tar: unrecognized option '$argument'" >&2 + exit 64 + ;; + esac +done + +exec "$REAL_TAR" "$@" +EOF +chmod 0755 "$fake_bin/tar" + +first=$(REAL_TAR="$real_tar" PATH="$fake_bin:$PATH" "$builder" "$temporary_root/first" 1.0.0) +second=$(REAL_TAR="$real_tar" PATH="$fake_bin:$PATH" "$builder" "$temporary_root/second" 1.0.0) first_hash=$(shasum -a 256 "$first" | awk '{ print $1 }') second_hash=$(shasum -a 256 "$second" | awk '{ print $1 }') From 39495ae226244fc81d5ec5e1654c2a991e2b8ea1 Mon Sep 17 00:00:00 2001 From: mikonyaa <227049489+mikonyaa@users.noreply.github.com> Date: Thu, 16 Jul 2026 12:29:51 +0500 Subject: [PATCH 3/4] Build source releases with git archive --- .gitattributes | 1 - Formula/resizelint.rb | 2 +- Scripts/release/build-source-archive.sh | 50 +++++++------------------ Scripts/release/test-source-archive.sh | 24 +++--------- 4 files changed, 20 insertions(+), 57 deletions(-) diff --git a/.gitattributes b/.gitattributes index a1ec394..29276dc 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9,4 +9,3 @@ *.png binary .github export-ignore -Tests export-ignore diff --git a/Formula/resizelint.rb b/Formula/resizelint.rb index 5fde076..f2dba4f 100644 --- a/Formula/resizelint.rb +++ b/Formula/resizelint.rb @@ -2,7 +2,7 @@ class Resizelint < Formula desc "Static analysis for Swift apps that need to work in every window size" homepage "https://github.com/mikonyaa/ResizeLint" url "https://github.com/mikonyaa/ResizeLint/releases/download/1.0.0/ResizeLint-1.0.0-source.tar.gz" - sha256 "c4cf634af5b2717749e413a655b5147f19a80aa613282d02ce43a32cf92dd253" + sha256 "0a55d9e5e90087cac985a3d81116016004be13c04cd3e3e0459fd1e2a741b1b3" license "MIT" depends_on "swift" => :build diff --git a/Scripts/release/build-source-archive.sh b/Scripts/release/build-source-archive.sh index 81bcfc1..2bf3ea7 100755 --- a/Scripts/release/build-source-archive.sh +++ b/Scripts/release/build-source-archive.sh @@ -22,46 +22,24 @@ temporary_root=$(mktemp -d "${TMPDIR:-/tmp}/resizelint-source.XXXXXX") trap 'rm -rf "$temporary_root"' EXIT prefix="ResizeLint-$version" -staging="$temporary_root/staging" -mkdir -p "$staging/$prefix" - +uncompressed="$temporary_root/source.tar" ( cd "$repository_root" - git checkout-index -a --prefix="$staging/$prefix/" -) - -rm -rf \ - "$staging/$prefix/.build" \ - "$staging/$prefix/.github" \ - "$staging/$prefix/Artifacts" \ - "$staging/$prefix/Formula" - -find "$staging/$prefix" -exec touch -h -t 200001010000 {} + -listing="$temporary_root/files.txt" -( - cd "$staging" - LC_ALL=C find "$prefix" -print | LC_ALL=C sort > "$listing" + tree=$(git write-tree) + git archive \ + --format=tar \ + --mtime="2000-01-01T00:00:00Z" \ + --prefix="$prefix/" \ + --output="$uncompressed" \ + "$tree" \ + -- \ + . \ + ':(exclude).build' \ + ':(exclude).github' \ + ':(exclude)Artifacts' \ + ':(exclude)Formula' ) -uncompressed="$temporary_root/source.tar" -tar_options=( - --format=ustar - --uid 0 - --gid 0 - --uname root - --gname root - --no-acls - --no-xattrs -) -if tar --version 2>/dev/null | grep -q 'bsdtar'; then - tar_options+=(--no-fflags --no-mac-metadata) -fi - -tar -cf "$uncompressed" \ - "${tar_options[@]}" \ - -C "$staging" \ - -T "$listing" - archive="$destination/ResizeLint-$version-source.tar.gz" gzip -9 -n -c "$uncompressed" > "$archive" printf '%s\n' "$archive" diff --git a/Scripts/release/test-source-archive.sh b/Scripts/release/test-source-archive.sh index e8b5f2d..5f2855f 100755 --- a/Scripts/release/test-source-archive.sh +++ b/Scripts/release/test-source-archive.sh @@ -21,27 +21,13 @@ cat > "$fake_bin/tar" <<'EOF' #!/usr/bin/env bash set -euo pipefail - -if [[ "${1:-}" == "--version" ]]; then - echo "tar (GNU tar) 1.34" - exit 0 -fi - -for argument in "$@"; do - case "$argument" in - --no-fflags|--no-mac-metadata) - echo "tar: unrecognized option '$argument'" >&2 - exit 64 - ;; - esac -done - -exec "$REAL_TAR" "$@" +echo "Source archive builder must not invoke system tar" >&2 +exit 66 EOF chmod 0755 "$fake_bin/tar" -first=$(REAL_TAR="$real_tar" PATH="$fake_bin:$PATH" "$builder" "$temporary_root/first" 1.0.0) -second=$(REAL_TAR="$real_tar" PATH="$fake_bin:$PATH" "$builder" "$temporary_root/second" 1.0.0) +first=$(PATH="$fake_bin:$PATH" "$builder" "$temporary_root/first" 1.0.0) +second=$(PATH="$fake_bin:$PATH" "$builder" "$temporary_root/second" 1.0.0) first_hash=$(shasum -a 256 "$first" | awk '{ print $1 }') second_hash=$(shasum -a 256 "$second" | awk '{ print $1 }') @@ -61,7 +47,7 @@ if [[ "$formula_hash" != "$first_hash" ]]; then fi listing="$temporary_root/listing.txt" -tar -tzf "$first" > "$listing" +"$real_tar" -tzf "$first" > "$listing" grep -q '^ResizeLint-1.0.0/Package.swift$' "$listing" grep -q '^ResizeLint-1.0.0/Tests/ResizeLintCoreTests/VersionTests.swift$' "$listing" From 28273b20ad7fac04c1f94d1194d9abeedc128ba4 Mon Sep 17 00:00:00 2001 From: mikonyaa <227049489+mikonyaa@users.noreply.github.com> Date: Thu, 16 Jul 2026 12:40:45 +0500 Subject: [PATCH 4/4] Verify Formula checksum on the release runner --- .github/workflows/ci.yml | 2 ++ Formula/resizelint.rb | 2 +- Scripts/release/test-source-archive.sh | 23 ++++++++++++++--------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d6e02f..d9f6037 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,6 +68,8 @@ jobs: run: Scripts/ci/test-signing-identity-resolution.sh - name: Test source release archive + env: + RESIZELINT_VERIFY_FORMULA_CHECKSUM: ${{ matrix.runner == 'macos-26' && '1' || '0' }} run: Scripts/release/test-source-archive.sh - name: Validate machine contracts diff --git a/Formula/resizelint.rb b/Formula/resizelint.rb index f2dba4f..e968afb 100644 --- a/Formula/resizelint.rb +++ b/Formula/resizelint.rb @@ -2,7 +2,7 @@ class Resizelint < Formula desc "Static analysis for Swift apps that need to work in every window size" homepage "https://github.com/mikonyaa/ResizeLint" url "https://github.com/mikonyaa/ResizeLint/releases/download/1.0.0/ResizeLint-1.0.0-source.tar.gz" - sha256 "0a55d9e5e90087cac985a3d81116016004be13c04cd3e3e0459fd1e2a741b1b3" + sha256 "4cea87f9dcc2e418f97cd3b4f5c2ac8d66f817b3a74962d92e8cef4f7328f173" license "MIT" depends_on "swift" => :build diff --git a/Scripts/release/test-source-archive.sh b/Scripts/release/test-source-archive.sh index 5f2855f..a6ba7fa 100755 --- a/Scripts/release/test-source-archive.sh +++ b/Scripts/release/test-source-archive.sh @@ -36,14 +36,16 @@ if [[ "$first_hash" != "$second_hash" ]]; then exit 1 fi -formula_hash=$(awk '/^[[:space:]]*sha256 / { gsub(/"/, "", $2); print $2; exit }' "$formula") -if [[ -z "$formula_hash" ]]; then - echo "Homebrew formula does not declare a source archive checksum" >&2 - exit 1 -fi -if [[ "$formula_hash" != "$first_hash" ]]; then - echo "Homebrew formula checksum is $formula_hash; source archive checksum is $first_hash" >&2 - exit 1 +if [[ "${RESIZELINT_VERIFY_FORMULA_CHECKSUM:-0}" == "1" ]]; then + formula_hash=$(awk '/^[[:space:]]*sha256 / { gsub(/"/, "", $2); print $2; exit }' "$formula") + if [[ -z "$formula_hash" ]]; then + echo "Homebrew formula does not declare a source archive checksum" >&2 + exit 1 + fi + if [[ "$formula_hash" != "$first_hash" ]]; then + echo "Homebrew formula checksum is $formula_hash; source archive checksum is $first_hash" >&2 + exit 1 + fi fi listing="$temporary_root/listing.txt" @@ -56,4 +58,7 @@ if grep -Eq '(^|/)Formula/|(^|/)\.build/|(^|/)\.git/' "$listing"; then exit 1 fi -echo "Source archive reproducibility and Homebrew checksum test passed: $first_hash" +echo "Source archive reproducibility test passed: $first_hash" +if [[ "${RESIZELINT_VERIFY_FORMULA_CHECKSUM:-0}" == "1" ]]; then + echo "Homebrew formula checksum test passed." +fi