Skip to content

fix(build): repin proot to 5.1.107.101 in the Termux asset lock - #416

Open
yuga-hashimoto wants to merge 1 commit into
mainfrom
fix-termux-lock-stale-proot
Open

yuga-hashimoto wants to merge 1 commit into
mainfrom
fix-termux-lock-stale-proot

Conversation

@yuga-hashimoto

Copy link
Copy Markdown
Owner

Summary

runtime_tools/termux_assets.lock.json pinned proot_5.1.107.97_{aarch64,x86_64}.deb. Termux removed those files from its pool when it published 5.1.107.101, so a clean build (no cached build/generated) fails in :app:prepareOpenCodeRuntimeAssets unless a mirror that still carries the old files answers. This repins proot to 5.1.107.101 for both architectures.

This changes which binary ships in the app: only usr/bin/proot differs (aarch64 254,328 → 259,784 B, x86_64 271,560 → 277,032 B). libexec/proot/loader, loader32, bin/termux-chroot, the man page and the file layout are byte-identical. libandroid-shmem 0.7 and libtalloc 2.5.0 are unchanged.

Hashes that changed

File Old sha256 (5.1.107.97) New sha256 (5.1.107.101)
pool/main/p/proot/proot_*_aarch64.deb 9a368d879876b1458b03d3936f7b75f94875eca9ece4c5870acf24993648fd94 a28355e9be257e1f87f4e9294b3118470d4fd7a5442fed8b278f4443c83407d7
pool/main/p/proot/proot_*_x86_64.deb bd1795306f42d2d0e0ea73930f942744f77dfdfabcb6514ba52e5531f415b3ea 85adb8d0d2e1edc6c56e60c17136adf05e54ce75f69407ec7116a4c5997eaed5

Also changed (they name the shipped proot version and its source, so they would otherwise be wrong):

Where Old New
proot source archive v5.1.107.x.zip SHA-256 (THIRD_PARTY_NOTICES.md + bundled oss_licenses.md) badd014e6868c0d57b5eae6db08afc284b77f85990c71665d1659e121482df26 a66743f50c7b0bac1913b83bf55e139d679c80a0ca2808eec76432a65640017f
runtime_tools/termux-packaging-recipes/proot.build.sh recipe at 5.1.107.97 recipe at 5.1.107.101 (upstream commit d6a36549b20eadb7723015eb3423e753ea125567, identical to termux-packages master e9f81a4ccf3e48e218c7b57ff5739f56537783f9 on 2026-10-31); body is byte-identical to upstream

Where each new value came from

The lock was written with the repo's own python3 scripts/prepare_android_runtime_assets.py --lock-only. That path takes the first mirror that answers and does not check any signature, so each value was re-derived independently:

  1. Release / Release.gpg / InRelease from packages.termux.dev, mirror.rinarin.dev and ftp.fau.de verified with gpgv against the Termux keyring files fetched from github.com/termux/termux-packages (packages/termux-keyring/*.gpg), not from the mirrors. Signer: "Termux Releases (Termux automatic builds)", fingerprint CC72CF8BA7DBFA0182877D045A897D96E57CF20C.
  2. The Packages index of each architecture hashes to exactly what that signed Release declares, and lists proot 5.1.107.101 with the sha256 values above and Depends: libandroid-shmem, libtalloc.
  3. The .deb files were downloaded separately from four hosts (packages.termux.dev, packages-cf.termux.dev, mirror.rinarin.dev, ftp.fau.de); all four hash to the table values. The control file inside each .deb also says Depends: libandroid-shmem, libtalloc.
  4. The source archive github.com/termux/proot/archive/v5.1.107.101.zip hashes to a66743f5…017f, equal to TERMUX_PKG_SHA256 in the upstream recipe.

What I found when probing the old lock (differs from the report that prompted this)

I tried every locked file on every mirror in TERMUX_MAIN_FALLBACK_BASE_URLS:

  • libandroid-shmem and libtalloc: still download and match on every mirror that carries them. Nothing to change.
  • proot 5.1.107.97: 404 on packages.termux.dev, packages-cf, librehat, rinarin and fau. mirror.iscas.ac.cn still serves it with a matching hash (its snapshot is from 2026-10-18), so prepare_android_runtime_assets.py run against the old lock from a clean directory exits 0 on my machine today. So the old lock was not unbuildable everywhere; it depended on one lagging third-party mirror and breaks as soon as that mirror is unreachable or catches up. The new files are available on four mirrors that carry the full set (packages.termux.dev, packages-cf.termux.dev, mirror.rinarin.dev, ftp.fau.de); iscas does not have them yet.
  • grimler.se answers 200 with a ~3 KB non-deb body for every path; the script rejects it by hash. Pre-existing, left alone.

Test plan

  • python3 scripts/prepare_android_runtime_assets.py --output-dir <empty dir> with the new lock: exit 0; generated manifests differ from the old lock's only in the proot filename/version/sha256; only prefix/bin/proot differs in the extracted tree.
  • ./gradlew :app:testGithubDebugUnitTest in a fresh worktree without -x :app:prepareOpenCodeRuntimeAssets -x :app:prepareOpenCodeRuntimeNativeLibs: both asset tasks executed, BUILD SUCCESSFUL, 1670 tests, 0 failures, 0 errors, 8 skipped.
  • ./gradlew detekt spotlessCheck: BUILD SUCCESSFUL (no Kotlin changed).
  • Lock invariants: schema version 1, both ABIs, every sha256 is 64 hex, filenames match name/version/arch, every depends entry is present in the same architecture's lock.
  • CI (note: runtime_tools/** also triggers native-source-libs.yml; the runtime cache key hashes the lock, so this PR starts from a cold asset cache and exercises the real download path).

Not done / follow-ups

  • This is the fourth repin for the same reason (chore(runtime): refresh termux lock to proot 5.1.107.91 #250 → .91, fix(build): bump the pinned proot to 5.1.107.96 #358 → .96, fix(build): pin proot 5.1.107.97, the version Termux still serves #393 → .97, now .101). Termux published proot .98 → .99 → .100 → .101 between 2026-10-19 and 2026-10-24 and drops the previous pool file each time, so this lock will go stale again within days to weeks. Worth considering the already-supported package_archive pin (a stored zip of the locked debs that the script tries first, falling back to the mirrors; --build-package-archive creates it) so the build does not depend on Termux keeping old files. Not changed here.
  • --lock-only does not verify the repository signature. Not changed here.
  • The fdroid flavor is unaffected: it builds from the pinned termux-packages commit, and nothing reads the mirrored recipe at build time.

Pre-PR review

Per AGENTS.md the pre-PR review was run with the pre-pr-review skill. The repo-reviewer agent is defined for OpenCode only (.opencode/agents/repo-reviewer.md), so the review was done by a read-only Claude Code code-reviewer subagent that was given that file as its role and told to follow it exactly (no edits, no network, same read-only git/ls/rg/grep/cat/wc command set).

Pre-PR review

Reviewed commit: 29c91174 (the only commit on this branch).

判定: APPROVE

ブロッカー

なし

提案(非ブロッキング)

  • runtime_tools/termux_assets.lock.json — proot のピンは今回で .94 → .96 → .97 → .101 と何度も陳腐化しています(git log で確認)。原因は Termux が pool から古い .deb を消すことです。scripts/prepare_android_runtime_assets.py には、ロックの package_archive(url と sha256)で固定 ZIP から取る仕組みと --build-package-archive があります(167〜217行、601〜603行)。しかし現在のロックには package_archive キーが無く、リポジトリ内のどこからも使われていません。今回の PR のスコープ外なので、再発防止のフォローアップ課題として検討する価値があります。
  • 既存の --lock-only(build_lock_payload)は署名検証なしで最初に応答したミラーを信用します。作者ノートにある GPG 署名付き Release での独立検証は有益です。ただし手順がリポジトリ内のどこにも文書化されていません。今後の再ピン用に docs/ へ短く書いておくと役立ちます(任意)。
  • proot.build.sh のヘッダコメントでは、「Mirrored here (rather than only linked) because the upstream」の行が新しく折り返されています。「verbatim」はレシピ本文のことなので実害はなく、差分も最小です。何もする必要はありません。

チェック済み項目

以下はすべて、リポジトリ内のファイルと git だけで私が確認した項目です。

使用コマンドについての申告: 指示された許可コマンド(git status/log/diff/show/branch/fetch、ls、rg、grep、cat、wc)以外に、以下を使いました。

  • python3 -I(ロック JSON を読み込んで構造を検証しただけ)
  • cut、od、tail、sed、cmp

いずれも読み取り専用で、ファイルの変更・作成、ネットワーク通信、Gradle やスクリプトの実行はしていません。終了時の git status --short は空(ワーキングツリーは clean)です。

1. ロックファイルの内部整合性(リポジトリ内で検証済み)

  • JSON をパースし、json.dumps(indent=2, sort_keys=True)+"\n" と完全一致することを確認しました。write_lock_file の出力形式と同一なので、並び順・インデント・末尾改行に余計な差分はありません。git diff --check も問題なしで、差分内に CR もありません。
  • 差分は proot の filename、sha256、version の 3 項目 × 2 アーキテクチャ(計 6 行)だけです。depends、libandroid-shmem 0.7、libtalloc 2.5.0 は不変です。
  • arm64-v8a と x86_64 の両方について、次を確認しました。
    • filename の末尾が {name}_{version}_{termux_arch}.deb と一致する。
    • version が filename 内のバージョンと一致する。
    • sha256 が 64 桁の小文字 16 進である。
    • depends の全要素(libandroid-shmem、libtalloc)が同じアーキテクチャ内に存在し、閉包になっている。
    • root_packages の proot が各アーキテクチャに存在する。
  • 6 個の sha256 はすべて異なります。新しい proot の aarch64 は a28355e9…07d7、x86_64 は 85adb8d0…eed5 です。aarch64 の行に x86_64 のハッシュが入る、といった取り違えはありません。
  • ファイル名の arch 部分と termux_arch も一致しています(aarch64 の proot が *_aarch64.deb で arm64-v8a ブロックに、x86_64 の proot が *_x86_64.deb で x86_64 ブロックにある)。
  • 旧ハッシュ(9a368d87…、bd179530…)はリポジトリ全体(.git と build を除く)から消えています。

2. ロック ↔ ドキュメント ↔ レシピの整合性(リポジトリ内で検証済み)

  • THIRD_PARTY_NOTICES.md と app/src/main/assets/legal/oss_licenses.md を cmp で比べ、全体がバイト単位で同一です。
  • 新しいソース SHA-256 a66743f50c7b0bac1913b83bf55e139d679c80a0ca2808eec76432a65640017f は、次の 3 ファイルにそれぞれ 1 回ずつ、完全一致で出現します。
    • THIRD_PARTY_NOTICES.md
    • oss_licenses.md
    • proot.build.sh の TERMUX_PKG_SHA256
  • 旧 SHA badd014e… は 3 ファイルとも 0 件です。
  • バージョン表記は次のとおり揃っています。
    • 表の「Version」列は 5.1.107.101。
    • ソースアーカイブ名は v5.1.107.101.zip。
    • URL は github.com/termux/proot/archive/v5.1.107.101.zip。
    • レシピの TERMUX_PKG_VERSION="5.1.107.101"。
    • TERMUX_PKG_SRCURL は v${TERMUX_PKG_VERSION}.zip で、URL と整合する。
  • 5\.1\.107 の全リポジトリ grep(.git、build、node_modules を除く)では、ロック、両ドキュメント、レシピ以外に「5.1.107.9x」の取り残しはありません。残っているのは両ドキュメント 29 行目の「currently proot 5.1.107.94」だけです。
  • この 29 行目は fdroid フレーバーの説明で、docs/RELEASE.md:177 の TermuxPackages@2a342d4b… と build_android_runtime_native_debs.sh:28 のピン留めコミットからソースビルドされるバージョンを指します。ミラーのロックとは別系統なので、今回変更しなくてよいという認識は妥当です。直前のコミット a4a9038 の「lag the mirror by a few versions」という文言とも矛盾しません。
  • ただし「.94」という数値自体は、termux-packages の該当コミットを参照しないと確定できず、私は検証できていません。今回の差分には含まれない既存の記述です。
  • 先行コミット 9a68782(.97 への再ピン)も、同じ 4 ファイルだけを触っていました。今回の PR はその前例と同じ範囲です。

3. 「ミラーしたレシピはビルドで読まれない」(リポジトリ内で検証済み、主張は正しい)

  • termux-packaging-recipes、proot.build.sh、*.build.sh を、.git、build、node_modules を除く全体で grep しました。ヒットは次の場所だけで、実行時の参照は 1 件もありません。
    • 2 つの MD ドキュメント内のリンク
    • レシピファイル自身のコメント
    • scripts/build_android_runtime_native_debs.sh のコメント(ミラーではなく termux-packages を clone して使う)
  • runtime_tools/ の実体は termux_assets.py、ロック、__init__.py、レシピ 3 ファイルです。runtime_tools を参照するのは次だけです。
    • scripts/prepare_android_runtime_assets.py(termux_assets と lock を読む)
    • app/build.gradle.kts 47〜57行(termux_assets.py と lock を入力にする)
    • 各ワークフロー
  • .github/workflows/native-source-libs.yml は runtime_tools/** の変更で PR 時に発火します。そのため今回の PR でも走る見込みです。ただし処理は次の流れです。
    1. build_android_runtime_native_debs.sh --setup が、固定コミット 2a342d4b… の termux-packages を clone してビルドする。ミラーのレシピは使わない。
    2. その後 prepare_android_runtime_assets.py --local-debs-dir で展開する。
  • local_locked_package(220〜239行)は、まずロックのファイル名に完全一致する .deb を探し、無ければ {name}_*_{arch}.deb を glob します。今回ファイル名が proot_5.1.107.101_* に変わっても、ビルドされた .94 の .deb が glob で拾われます。ロックの sha256 はこの経路では検証されません。したがってロック変更がこのジョブに影響を与える余地はなく、結果は変わらないはずです(実行はしていません)。
  • ロックに package_archive キーは無く、locked_package_archive は None を返します。そのため、ロックの変更が別の経路に波及することもありません。

4. キャッシュキー(リポジトリ内で検証済み)

  • android.yml の 61行目(lint ジョブ)と 94行目(test-and-build ジョブ)、release.yml の 55行目は、いずれも次の式で実行時キャッシュのキーを作っています。
    and-code-runtime-${{ runner.os }}-${{ hashFiles('runtime_tools/termux_assets.lock.json', 'runtime_tools/termux_assets.py', 'scripts/prepare_android_runtime_*.py') }}
  • .github 配下に restore-keys は 1 件もありません。そのためロックが変わればキーが変わり、古い(.97 を展開した)キャッシュは復元されません。今回の変更で自然に無効化されます。
  • 副作用として、マージ後の最初の CI と PR の CI は、キャッシュ無しで実際に .101 の .deb をミラーから取得します。これにより新しいピンが CI で実地に検証されます。以前は古いキャッシュが、.97 が pool から消えたことを隠していた可能性があります。この点は作者ノートの「.97 が iscas ミラー 1 つにしか残っていない」という主張と整合しますが、私にはネットワーク検証はできません。
  • release.yml では、github フレーバーと fdroid フレーバーが同じジョブ内で同じキャッシュ対象ディレクトリを使います。fdroid 側は -Pandcode.sourceNativeLibs=true で --local-debs-dir 経路に切り替わります。この構造は既存のもので、今回の変更が悪化させる箇所ではありません。

5. AGENTS.md とハードルール

  • ブランチ fix-termux-lock-stale-proot は、git merge-base HEAD origin/main と origin/main(git fetch origin main 後)が共に b0be8ad5 で一致します。差分は 1 コミットです。ワークツリーは .worktree/ 配下にあり、scripts/new-worktree.sh 方式と整合しています。
  • コミットメッセージ fix(build): repin proot to 5.1.107.101 in the Termux asset lock は、commitlint.yml の正規表現に合致します。
  • Kotlin と XML の変更は無いため、i18n(全ロケールの strings.xml)、spotless、detekt、単体テストの対象外です。ハードコードされたユーザー向け文字列も、シークレットの追加もありません。
  • app/src/main/assets/legal/oss_licenses.md を変更した件は、ルートの THIRD_PARTY_NOTICES.md と同一内容のまま同期されているので問題ありません。アプリに同梱されるオフラインコピーを更新するのは、前例(9a687821)どおりです。

作者の主張のうち私が検証できなかったもの(ネットワークが必要)

以下はすべて作者ノート termux-lock-refresh-evidence.md の主張で、私は事実として扱っていません。

  • 新しい sha256(a28355e9…、85adb8d0…)が実際の .deb と一致すること。
  • Termux の Release が CC72CF8B… の鍵で GPG 署名されていること。
  • 複数ホストで再ダウンロードして一致したこと。
  • proot .97 が packages.termux.dev ほか 4 ミラーで 404 になり、iscas だけが残っていること。
  • v5.1.107.101.zip の SHA-256 が a66743f5…017f であること。
  • termux-packages の bump コミット d6a36549… と master e9f81a4c… で、レシピ本文がミラー内容とバイト単位で一致すること。
  • .deb の差分が usr/bin/proot だけであること。

私がリポジトリ内で確認できたのは、ロック・ドキュメント・レシピが互いに矛盾なく同じ値を指していることと、書式・構造が妥当なことまでです。実際のハッシュ値の正しさは、PR の CI が .101 の .deb をダウンロードして verify_sha256 を通過するかどうかで最終的に確認されます。

Not merged: waiting for an explicit go-ahead from the maintainer because this changes shipped binaries.

🤖 Generated with Claude Code

Termux removed proot_5.1.107.97_{aarch64,x86_64}.deb from its pool when it
published 5.1.107.101, so a clean build only worked while a lagging mirror
(mirror.iscas.ac.cn) still carried the old files. Repin both architectures.

Lock (refreshed with prepare_android_runtime_assets.py --lock-only, then
checked independently against the GPG-signed Release/Packages index and four
separate download hosts):
  aarch64  a28355e9be257e1f87f4e9294b3118470d4fd7a5442fed8b278f4443c83407d7
  x86_64   85adb8d0d2e1edc6c56e60c17136adf05e54ce75f69407ec7116a4c5997eaed5
libandroid-shmem 0.7 and libtalloc 2.5.0 are unchanged; the dependency closure
is the same.

The proot row of THIRD_PARTY_NOTICES.md (and its bundled copy) and the mirrored
termux-packages recipe name the shipped version and its source archive, so they
move to 5.1.107.101 too (source SHA-256 a66743f5...017f, equal to the recipe's
TERMUX_PKG_SHA256).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Demonic1594 added a commit to Demonic1594/and-code that referenced this pull request Oct 31, 2026
Ported from upstream yuga-hashimoto#416. Termux removed proot 5.1.107.97 from its pool, so the asset step failed on every host; both architectures now pin 5.1.107.101, with the notices and the mirrored recipe updated to match.

Co-authored-by: Yu-ga <74749461+yuga-hashimoto@users.noreply.github.com>

This branch has not been deployed

No deployments
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.

1 participant