diff --git a/.github/workflows/xposed-release.yml b/.github/workflows/xposed-release.yml new file mode 100644 index 0000000..c03a4fe --- /dev/null +++ b/.github/workflows/xposed-release.yml @@ -0,0 +1,137 @@ +name: xposed-release + +# Mirrors a release from this (source) repo into the module's entry in the +# Xposed Modules Repository, which is what LSPosed's module browser actually +# reads from: https://github.com/Xposed-Modules-Repo/com.xiddoc.playintegrityalert +# +# The Xposed repo requires each release's TAG to be "-" +# (e.g. 123-1.0.0) and to carry the APK as an asset. Our own releases keep their +# human-friendly "v1.0.0" tags; this job re-tags the mirror to the required shape, +# uploads the same APK, and syncs the entry's README/SUMMARY/SOURCE_URL from the +# xposed-repo/ folder in this repo — so the entry is maintained entirely from here. +# +# Setup (one time): +# 1. The entry repo already exists at Xposed-Modules-Repo/com.xiddoc.playintegrityalert +# with you as a collaborator. Make sure its repo *description* is the module's +# display name ("Play Integrity Alert") — set in the entry repo's settings. +# 2. Create a CLASSIC PAT (github.com → Settings → Developer settings → Tokens +# (classic)) with the `public_repo` scope, and add it to THIS repo as the secret +# XPOSED_REPO_TOKEN (Settings → Secrets and variables → Actions). +# - The secret lives in THIS repo (where the workflow runs), NOT in the entry +# repo — so you don't need any secret access on Xposed-Modules-Repo. +# - It must be a CLASSIC token, not fine-grained: a classic PAT inherits your +# own access, which includes your collaborator write access to the entry +# repo. A fine-grained PAT can't target an org repo you only collaborate on. +# After that, every published release here is mirrored automatically. You can also +# re-run it by hand (workflow_dispatch) to repair the entry or push metadata-only +# edits against an existing release. + +on: + release: + types: [published] + workflow_dispatch: + inputs: + tag: + description: "Source release tag to mirror (default: latest release)" + required: false + +concurrency: + group: xposed-release + cancel-in-progress: false + +env: + # The entry repo — its NAME must equal the module's package name. + XPOSED_REPO: Xposed-Modules-Repo/com.xiddoc.playintegrityalert + +jobs: + mirror: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + # Full history + tags: the versionCode is the commit count at the tag, + # exactly as release.yml computes it when building the APK. + fetch-depth: 0 + + - name: Resolve the source release tag + id: src + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + tag="${{ github.event.release.tag_name || inputs.tag }}" + if [ -z "$tag" ]; then + tag="$(gh release view --repo "$GITHUB_REPOSITORY" --json tagName -q .tagName)" + fi + echo "Mirroring source release: $tag" + echo "tag=$tag" >> "$GITHUB_OUTPUT" + + - name: Derive the Xposed tag (VersionCode-VersionName) + id: xtag + run: | + set -euo pipefail + tag="${{ steps.src.outputs.tag }}" + name="${tag#v}" # v1.0.0 -> 1.0.0 (leaves bare names as-is) + git fetch --tags --force origin + # versionCode == commit count at the tagged commit; matches the APK, which + # release.yml builds with -PVERSION_CODE="$(git rev-list --count HEAD)". + code="$(git rev-list --count "$tag")" + xtag="${code}-${name}" + echo "Xposed tag: $xtag" + echo "name=$name" >> "$GITHUB_OUTPUT" + echo "xtag=$xtag" >> "$GITHUB_OUTPUT" + + - name: Download the source release APK + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + mkdir -p dist + gh release download "${{ steps.src.outputs.tag }}" \ + --repo "$GITHUB_REPOSITORY" \ + --pattern '*.apk' \ + --dir dist + ls -la dist + + - name: Sync entry metadata (README, SUMMARY, SOURCE_URL) + env: + GH_TOKEN: ${{ secrets.XPOSED_REPO_TOKEN }} + run: | + set -euo pipefail + if [ -z "${GH_TOKEN:-}" ]; then + echo "::error::XPOSED_REPO_TOKEN is not set — cannot push to $XPOSED_REPO. See this workflow's header for setup." + exit 1 + fi + tmp="$(mktemp -d)" + git clone "https://x-access-token:${GH_TOKEN}@github.com/${XPOSED_REPO}.git" "$tmp" + cp xposed-repo/README.md "$tmp/README.md" + cp xposed-repo/SUMMARY "$tmp/SUMMARY" + cp xposed-repo/SOURCE_URL "$tmp/SOURCE_URL" + cd "$tmp" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + if git diff --cached --quiet; then + echo "Entry metadata already up to date." + else + git commit -m "Sync entry metadata for ${{ steps.src.outputs.tag }}" + git push + fi + + - name: Publish the mirror release to the Xposed repo + env: + GH_TOKEN: ${{ secrets.XPOSED_REPO_TOKEN }} + run: | + set -euo pipefail + xtag="${{ steps.xtag.outputs.xtag }}" + notes="Play Integrity Alert ${{ steps.src.outputs.tag }} — mirrored from ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/tag/${{ steps.src.outputs.tag }}" + if gh release view "$xtag" --repo "$XPOSED_REPO" >/dev/null 2>&1; then + echo "Release $xtag already exists on $XPOSED_REPO — refreshing its APK asset." + gh release upload "$xtag" dist/*.apk --repo "$XPOSED_REPO" --clobber + else + gh release create "$xtag" dist/*.apk \ + --repo "$XPOSED_REPO" \ + --title "$xtag" \ + --notes "$notes" + fi + echo "Published $xtag to $XPOSED_REPO" diff --git a/xposed-repo/README.md b/xposed-repo/README.md new file mode 100644 index 0000000..2c0fb63 --- /dev/null +++ b/xposed-repo/README.md @@ -0,0 +1,45 @@ +

+ Play Integrity Alert +

+ +

Play Integrity Alert

+ +

+ Latest release + Downloads + Source stars + License +

+ +## About this module + +**Play Integrity Alert notifies you the moment an app asks for a Google Play +Integrity verdict.** + +Scope the module to Google Play Store, choose which apps you care about (or watch +them all), and whenever one of them calls the Play Integrity API you get a +notification — with the app's name — plus an in-app history of every detection. + +The Play Integrity client libraries don't compute a verdict in-process; they hand +the request to **Google Play Store** (`com.android.vending`, "Finsky"), and the +caller's package travels *inside* that request. So the module injects into the +**Play Store process only** and observes the integrity requests as they arrive — +it never alters the verdict, it only tells you it happened. + +This module behaves just like the +[GrapheneOS Play Integrity alert](https://x.com/GrapheneOS/status/1877790719009529972) +feature, and is inspired by it. + +## Usage + +1. Install the APK and **enable Play Integrity Alert** in LSPosed. +2. Open the module's **Scope** and tick **Google Play Store** (`com.android.vending`) + — that's the only app you need. It's a system app, so if you don't see it, enable + **Show system apps** from the scope screen's ⋮ menu and refresh. +3. **Restart Play Store** so the hook loads (the app has a button for this; with root + it's automatic). + +## Source & documentation + +Full source, build instructions, and issue tracker live in the upstream repository: +**https://github.com/Xiddoc/PlayIntegrityAlert** diff --git a/xposed-repo/SOURCE_URL b/xposed-repo/SOURCE_URL new file mode 100644 index 0000000..a7e8bb6 --- /dev/null +++ b/xposed-repo/SOURCE_URL @@ -0,0 +1 @@ +https://github.com/Xiddoc/PlayIntegrityAlert diff --git a/xposed-repo/SUMMARY b/xposed-repo/SUMMARY new file mode 100644 index 0000000..1ae62f2 --- /dev/null +++ b/xposed-repo/SUMMARY @@ -0,0 +1 @@ +Notifies you whenever an app requests a Google Play Integrity verdict. Scope it to Google Play Store.