Deterministic, reproducible Android/Bionic rootfs toolchain builder for the fparted rooted partition editor.
This repository produces signed, verified rootfs bundles for each supported Android ABI that the fparted app consumes during startup and toolchain installation.
- Package ID:
vn.shadichy.parted - Rootfs prefix:
/data/data/vn.shadichy.parted/files - No
/data/data/com.termuxartifacts allowed in any output - No
/files/usrpath leakage allowed in any output - No standard Termux prefix binaries from
com.termuxrepository
- Release manifests are signed with a real GPG key (ed25519). The private key lives only in the
GPG_PRIVATE_KEYrepository secret; the public key is committed atkeys/release-pubkey.asc. - Signing is mandatory: the
assemble-releasejob fails if the detached signature cannot be produced. - Tag pushes (v*..) publish releases automatically — no draft is created.
.
├── .github/workflows/
│ └── ci.yml # Single pipeline: PR validation + 2-ABI builds + verify-all + release assembly
├── config/
│ ├── packages.yaml # Package definitions with source hashes, licenses
│ ├── aliases.yaml # User-facing name → canonical target mapping
│ ├── required-binaries.yaml # Source-of-truth for required executables
│ └── termux-lock.json # Pinned termux/termux-packages commit + metadata
├── overlays/
│ ├── packages/ # Missing/modified package recipes
│ └── root-packages/ # Root-level recipe overlays
├── patches/
│ └── termux-prefix.patch # Custom prefix patch for fparted
├── scripts/
│ ├── resolve-packages.py # Alias validation + dependency graph resolution
│ ├── build-rootfs.sh # One-architecture rootfs build script
│ ├── assemble-rootfs.py # Deterministic bundle assembly + manifest generation
│ ├── validate-rootfs.py # ELF/path/dep/license/SBOM/smoke validation
│ └── make-release-manifest.py # Release manifest + SHA256SUMS + SPDX generation
├── keys/
│ └── release-pubkey.asc # Release signing public key (verifies release-manifest.sig)
├── schemas/
│ ├── release-manifest.schema.json
│ └── rootfs-manifest.schema.json
├── tests/ # Test fixtures and test scripts
└── README.md
python3 scripts/resolve-packages.py --graph parted --jsonbash scripts/build-rootfs.sh arm64-v8apython3 scripts/validate-rootfs.py \
--bundle staging/arm64-v8a/fparted-rootfs-*.zip \
--strictpython3 scripts/make-release-manifest.py \
--bundle-dir staging/ \
--toolchain-version 1.0.0 \
--termux-commit 436ebf0f917285fe86659e9d4e43c0d257256f75 \
--output-dir release-output| Android ABI | Termux Architecture |
|---|---|
arm64-v8a |
aarch64 |
x86_64 |
x86_64 |
Every release bundle must pass:
- Manifest schema validation —
schemas/release-manifest.schema.jsonandschemas/rootfs-manifest.schema.json - No path traversal / zip-slip — all archive entries use relative, non-
..paths - No forbidden prefixes — no
com.termuxor/files/usrpaths in any entry - Per-file SHA-256 hash verification — matches
rootfs-manifest.json - ELF architecture check — matches target ABI
- Required binary presence — all binaries in
required-binaries.yamlare present - Required binary execute bits — every required regular-file binary under
usr/bin/orbin/is owner-executable with no group/other execute bits ((mode & 0o111) == 0o100) inrootfs-manifest.json(symlink entries exempt) - License/SBOM coverage —
packages.spdx.jsonincluded in release - Forbidden prefix grep — CI fails if standard Termux prefix appears in output
Device validation is a manual gate performed by the maintainer outside CI: GitHub-hosted runners can never attach a rooted Android device, so the former smoke-test CI job was removed. After a release is published, validate the artifacts on a rooted Android device or an Android x86_64 emulator/VM connected via adb before announcing the release.
Artifacts needed (from the release):
fparted-rootfs-<version>-<abi>.zipfor the target ABI (arm64-v8aorx86_64)rootfs-manifest.json— embedded inside each bundle ZIP (extract the ZIP to obtain it)release-manifest.jsonrelease-manifest.sigSHA256SUMS
Procedure:
- Fetch the release assets for the target ABI (
arm64-v8aorx86_64). - Verify integrity:
(or compare each asset hash against
sha256sum -c SHA256SUMS
release-manifest.json). - Verify the manifest signature (run from a checkout of this repository):
gpg --import keys/release-pubkey.asc gpg --verify release-manifest.sig release-manifest.json
- Inspect the bundle: extract the zip to a scratch dir and confirm the rootfs layout matches
rootfs-manifest.json. ZIP entries are relative to the prefix — extraction showsusr/bin/...,lib/...at the archive root, while the installed layout places them underdata/data/vn.shadichy.parted/files. - Run on device: push/extract the bundle onto the device via adb and run required binaries from
config/required-binaries.yaml(includingparted,blkid,dd,test,mkswap,e2fsck,e2image,mke2fs,resize2fs,tune2fs,mkfs.fat,fsck.fat,fatlabel,mkfs.exfat,fsck.exfat,exfatlabel,mkfs.f2fs,fsck.f2fs,btrfs,mkfs.btrfs,btrfstune,cryptsetup,mkfs.ntfs,ntfsfix,ntfslabel,ntfsresize,mkfs.xfs,xfs_repair,xfs_admin,xfs_growfs,mkfs.jfs,jfs_fsck,jfs_tune,mkfs.hfsplus,fsck.hfsplus,mkfs.apfs,apfsck,fsck.apfs,bcachefs,lvm,pvcreate,vgcreate,lvcreate), verifying each prints a version/usage line and exits non-zero properly when invoked incorrectly. - Record the device/VM image, Android version, ABI, and results in the release notes or PR.
Permissions note: staging directories are normalized to
0700and files to owner-only modes (0700executables,0600data). The bundle's manifest records only file/symlink entries — directory entries are intentionally omitted (parents are implied) — so final directory modes are applied by the app-side installer. Files are executable only by the owning uid: once the app installs the toolchain, that uid is the app's own. When smoke-testing manually over adb, extraction runs as a different uid, so useadb rootandchmod/chownto make the binaries executable for the testing context if execution is denied.
The fparted app communicates with Repo A only through versioned manifests:
release-manifest.json— declares assets per ABI, schema version, toolchain version, Termux commit, prefix, ABI mapping, required binaries, and SHA-256 hashesrootfs-manifest.json— describes each entry inside the bundle (path, type, mode, hash, symlink target, package owner)
The app verifies signature, schema, package ID, prefix, ABI, size, and every asset SHA-256 before extraction.