Skip to content

fix: ship owner-only 0700/0600 modes and guard with validator check #35

fix: ship owner-only 0700/0600 modes and guard with validator check

fix: ship owner-only 0700/0600 modes and guard with validator check #35

Workflow file for this run

name: Build & Release
on:
push:
branches: [master]
tags: ["v[0-9]+.[0-9]+.[0-9]+"]
pull_request:
branches: [master]
workflow_dispatch:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
validate-configs:
name: Validate Configs & Schemas
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: python3 -m pip install pyyaml jsonschema
- name: Validate aliases
run: python3 scripts/resolve-packages.py --json
- name: Validate required binaries coverage
run: python3 scripts/resolve-packages.py --check-binaries --json
- name: Validate schemas
run: |
python3 << 'EOF'
import json
from jsonschema import Draft7Validator
for schema_file in ('schemas/release-manifest.schema.json',
'schemas/rootfs-manifest.schema.json'):
with open(schema_file) as f:
schema = json.load(f)
Draft7Validator.check_schema(schema)
print(f'{schema_file}: valid draft-07 schema')
EOF
- name: Install ShellCheck
run: sudo apt-get update && sudo apt-get install -y shellcheck
- name: ShellCheck
run: shellcheck --severity=warning scripts/*.sh
- name: Python lint
run: |
python3 -m py_compile scripts/resolve-packages.py
python3 -m py_compile scripts/assemble-rootfs.py
python3 -m py_compile scripts/validate-rootfs.py
python3 -m py_compile scripts/make-release-manifest.py
resolve-dependencies:
name: Resolve Dependency Graphs
runs-on: ubuntu-latest
strategy:
matrix:
package: [parted, e2fsprogs, dosfstools, exfatprogs, f2fs-tools, btrfs-progs]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: python3 -m pip install pyyaml
- name: Resolve build order
run: python3 scripts/resolve-packages.py --graph ${{ matrix.package }} --json
validate-sources:
name: Validate Pinned Source URLs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: python3 -m pip install pyyaml
- name: Check source hashes are pinned
run: |
python3 -c "
import yaml, sys
with open('config/packages.yaml') as f:
pkgs = yaml.safe_load(f)
unpinned = []
for name, pkg in pkgs.get('packages', {}).items():
if 'PLACEHOLDER' in pkg.get('source_hash', ''):
unpinned.append(name)
if unpinned:
print(f'ERROR: Unpinned source hashes for: {unpinned}')
sys.exit(1)
print('All source hashes are pinned')
"
reproducibility:
name: Reproducibility Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: python3 -m pip install pyyaml
- name: Verify forbidden prefixes
run: |
grep -r "com\.termux" overlays/ scripts/ || true
grep -r "files/usr" overlays/ scripts/ || true
- name: Check no hardcoded dev paths
run: |
grep -rE '/home/|/root/|/tmp/' \
--include='*.py' --include='*.sh' scripts/ || true
build-matrix:
name: Compute Build Matrix
needs: validate-configs
runs-on: ubuntu-latest
outputs:
include: ${{ steps.gen.outputs.include }}
steps:
- name: Generate matrix
id: gen
run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
echo 'include=[{"abi":"x86_64","termux-arch":"x86_64"}]' >> "$GITHUB_OUTPUT"
else
echo 'include=[{"abi":"arm64-v8a","termux-arch":"aarch64"},{"abi":"x86_64","termux-arch":"x86_64"}]' >> "$GITHUB_OUTPUT"
fi
build:
name: Build ${{ matrix.abi }}
needs: build-matrix
runs-on: ubuntu-latest
timeout-minutes: 240
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(needs.build-matrix.outputs.include) }}
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: python3 -m pip install pyyaml
- name: Resolve termux commit from lock file
id: lock
run: |
python3 -c "
import json
with open('config/termux-lock.json') as f:
print(json.load(f)['pinned_termux_commit'])
" > /tmp/termux-commit.txt
echo "termux_commit=$(cat /tmp/termux-commit.txt)" >> "$GITHUB_OUTPUT"
- name: Build rootfs for ${{ matrix.abi }}
run: |
bash scripts/build-rootfs.sh "${{ matrix.abi }}" "${{ steps.lock.outputs.termux_commit }}"
env:
TERMUX_APP__PACKAGE_NAME: vn.shadichy.parted
TERMUX__ROOTFS: /data/data/vn.shadichy.parted/files
TERMUX__PREFIX: /data/data/vn.shadichy.parted/files/usr
TERMUX_PREFIX: /data/data/vn.shadichy.parted/files/usr
TERMUX_PREFIX_SUBDIR: "usr"
ANDROID_ROOT: /system
- name: Validate bundle
run: |
BUNDLE=$(find "staging/${{ matrix.abi }}" -name "fparted-rootfs-*.zip" | head -1)
python3 scripts/validate-rootfs.py \
--bundle "${BUNDLE}" \
--manifest "staging/${{ matrix.abi }}/rootfs-manifest.json"
- name: Create artifact tarball
run: |
mkdir -p artifacts
tar -czf "artifacts/rootfs-${{ matrix.abi }}.tar.gz" \
-C "staging/${{ matrix.abi }}" \
--exclude='termux-checkout' \
--exclude='termux-build-cache' \
--exclude='rootfs' \
--exclude='packages' \
.
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: rootfs-${{ matrix.abi }}
path: artifacts/rootfs-${{ matrix.abi }}.tar.gz
retention-days: 30
verify-all:
name: Verify All ABIs Present
needs: build
if: github.event_name != 'pull_request' && github.ref_type == 'branch'
runs-on: ubuntu-latest
steps:
- name: Download all ABI artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Verify both ABI bundles present
run: |
for abi in arm64-v8a x86_64; do
if [[ -f "artifacts/rootfs-${abi}/rootfs-${abi}.tar.gz" ]]; then
echo "OK: ${abi}"
else
echo "ERROR: missing artifact for ${abi}"
exit 1
fi
done
- name: Forbid standard Termux prefix in outputs
run: |
mkdir -p /tmp/prefix-check
for tarball in artifacts/*/*.tar.gz; do
tar -xzf "${tarball}" -C /tmp/prefix-check
done
if find /tmp/prefix-check -type f \
\( -name "*.json" -o -name "*.sh" -o -name "*.md" -o -name "*.txt" -o -name "*.py" \) \
-exec grep -l "com\.termux" {} + 2>/dev/null | grep -q .; then
echo "ERROR: forbidden com.termux prefix found"
exit 1
fi
echo "No forbidden prefix found"
assemble-release:
name: Assemble Release Assets
needs: build
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: python3 -m pip install pyyaml jsonschema
- name: Download all ABI artifacts
uses: actions/download-artifact@v4
with:
path: release-assets
- name: Extract artifact tarballs
run: |
mkdir -p release-output
for tarball in release-assets/*/*.tar.gz; do
echo "Extracting ${tarball}"
tar -xzf "${tarball}" -C release-output/
done
- name: Version bundle filenames to tag
run: |
VERSION="${GITHUB_REF#refs/tags/v}"
for bundle in release-output/fparted-rootfs-*.zip; do
abi=$(basename "${bundle}" .zip | grep -oP '(?:arm64-v8a|x86_64)$')
mv "${bundle}" "release-output/fparted-rootfs-${VERSION}-${abi}.zip"
done
ls -1 release-output/fparted-rootfs-*.zip
- name: Import release signing key
run: echo "${{ secrets.GPG_PRIVATE_KEY }}" | gpg --batch --yes --import
- name: Assemble release manifest
run: |
python3 scripts/make-release-manifest.py \
--bundle-dir release-output \
--toolchain-version "${GITHUB_REF#refs/tags/v}" \
--termux-commit "$(python3 -c "import json; print(json.load(open('config/termux-lock.json'))['pinned_termux_commit'])")" \
--output-dir release-output \
--sign
- name: Verify release manifest signature
run: |
gpg --batch --import keys/release-pubkey.asc
gpg --verify release-output/release-manifest.sig release-output/release-manifest.json
- name: Validate generated release manifest
run: |
python3 << 'EOF'
import json
import jsonschema
with open('schemas/release-manifest.schema.json') as f:
schema = json.load(f)
with open('release-output/release-manifest.json') as f:
manifest = json.load(f)
jsonschema.validate(manifest, schema)
print('release-manifest.json validates against release-manifest.schema.json')
EOF
- name: Verify required binaries declared in config
run: python3 scripts/resolve-packages.py --check-binaries
- name: Verify bundle count
run: |
COUNT=$(find release-output -name "fparted-rootfs-*.zip" | wc -l)
echo "Bundles in release: ${COUNT}"
if [ "${COUNT}" -ne 2 ]; then
echo "ERROR: Expected 2 ABI bundles, got ${COUNT}"
exit 1
fi
- name: Verify hashes
run: |
cd release-output
sha256sum -c SHA256SUMS
- name: Upload release assets
uses: softprops/action-gh-release@v2
with:
files: |
release-output/fparted-rootfs-*.zip
release-output/release-manifest.json
release-output/release-manifest.sig
release-output/SHA256SUMS
release-output/packages.spdx.json
release-output/source-offer.json
draft: false
fail_on_unmatched_files: true