Dashboard compared module.prop versions (e.g. 0.6.2) directly against
BuildConfig.VERSION_NAME (which carries the git-describe suffix
0.6.2-14-g1f2205e on dev builds), always flagging mismatch. Now uses
baseVersion() to strip -N-gSHA before comparison; pre-release tags
(-rc1, -beta) are preserved.
Adds unit tests for normalizeVersion, compareSemver, baseVersion and
versionsMismatch, and wires :app:testDebugUnitTest into CI so they
actually run.
Two tweaks driven by the same goal — make the artifact list on the CI
run page less ambiguous and give the release step a review gate.
- The APK artifact was named `vpnhide`, which blends in with the other
module-zip artifacts (`vpnhide-kmod-*`, `vpnhide-zygisk`,
`vpnhide-ports`). Rename to `vpnhide-apk` so every entry in the
Artifacts list names the thing you actually get when you download it.
- Release-on-tag job now creates a DRAFT GitHub release instead of
publishing directly. Gives a chance to eyeball the release notes and
attached binaries before they go public, and avoids racing
update-json.sh against the assets becoming reachable.
docs/releasing.md and the release.py post-run hints updated to reflect
the manual Publish step and the fact that update-json still has to
wait for the release to be *published*, not just drafted (draft
release assets sit behind auth).
Yesterday's Phase 2 commit left the zygisk and portshide CI artifacts
carrying a "-dirty" suffix in their module.prop version: CI appended
`updateJson=...` to the committed module.prop *before* calling
build-zip.sh, so when build-version.sh ran inside the script it saw
the dirtied working tree and `git describe --dirty` appended "-dirty".
Move the updateJson injection into build-zip.sh itself, gated on an
UPDATE_JSON_URL env var. CI sets the env var via the job step `env:`
block; committed module.prop files are no longer touched. Local dev
builds leave the var unset and ship without updateJson, matching the
previous behaviour.
kmod CI already did things in the right order (version computed
before any module.prop edits); left that step as-is.
Add scripts/build-version.sh — a single source of truth for the
effective version string:
* HEAD on tag vX.Y.Z -> "X.Y.Z"
* N commits past tag -> "X.Y.Z-N-gSHA"
* working tree dirty -> additional "-dirty" suffix
* no git / no matching tag -> VERSION file fallback
Wired into every packaging path:
* zygisk/build-zip.sh and portshide/build-zip.sh now stage a copy of
module/ and sed-patch `version=` in the staging copy, so committed
module.prop files stay at the last-released version.
* kmod/build-zip.sh now builds into a staging copy too.
* The kmod CI step runs build-version.sh and sed-patches module.prop
before zipping (git installed in the DDK container).
* lsposed/app/build.gradle.kts exec's build-version.sh at configure
time and assigns the result to `versionName` (versionCode stays
static, still bumped by release.py).
All actions/checkout@v6 gained `fetch-depth: 0` so git describe sees
the full tag history inside CI containers.
Result: a locally built or CI-from-main APK shows up in Android
Settings as e.g. `0.6.1-16-gf86e5e5`, and the zip inside carries the
same string in module.prop; the Magisk/KSU manager displays it in the
update list. Release tag builds are indistinguishable from before —
clean `X.Y.Z`. Diagnostic bug reports now carry the exact commit in
the App version line of device_info.txt.
Split the generated markdown into two files:
- CHANGELOG.md at repo root — full history with the Keep a Changelog
header. Human-facing, discoverable from the GitHub repo page.
- update-json/changelog.md — still truncated to the last 5 versions,
for the Magisk/KSU update popup.
Both are regenerated from changelog.json on every changelog-add.py
and update-version.py run.
Also switch the CI release-notes extraction to read CHANGELOG.md so
the body is future-proof once a tag ages out of the short popup file.
Extract the current tag's section from update-json/changelog.md with
awk and pass it as body_path to softprops/action-gh-release. Keeping
generate_release_notes=true so GitHub still appends the auto PR list
and "Full Changelog" link below our handwritten summary.
Bumps actions/checkout v4→v6, actions/cache v4→v5,
actions/upload-artifact v4→v7, actions/download-artifact v4→v8
to silence the Node.js 20 deprecation warnings GitHub is emitting
ahead of the June 2026 cutoff.
softprops/action-gh-release stays on v2 (third-party, wasn't in the
deprecation list and v3 would need a separate compatibility review).
Mirror the kmod/zygisk plumbing so KernelSU-Next / Magisk pick up
portshide updates automatically:
- scripts/update-version.sh bumps portshide/module/module.prop along
with the other modules when VERSION changes
- scripts/update-json.sh writes update-json/update-ports.json pointing
at the current release zip
- CI appends updateJson=.../update-ports.json to the portshide
module.prop before zipping, matching kmod/zygisk
- Dashboard reports portshide version mismatches as issues, with the
same up/down/different wording the other modules use
Adds a portshide job mirroring the simple kmod zip packaging (no build
needed, just zip the module directory). Artifact lands next to the
other release zips so the gh-release step picks it up for tagged
builds.
- update-version.sh generates per-KMI update JSON files for kmod and one
for zygisk, pointing to GitHub Release artifacts
- CI injects updateJson URL into module.prop before packaging zips
- module.prop in repo stays clean (no updateJson), CI appends it per-variant
- Update version mismatch issue texts to direct users to KernelSU/Magisk
Modules for updating
- Fix versionName/versionCode back to 0.4.2 (was accidentally 0.4.3 from
test bump)
- Replace top bar filter icon with inline "Show system apps" checkbox
- Add hint card explaining L/K/Z layer toggles and Zygisk caveat
- Move showSystem state inside AppPickerScreen
- Fix RELEASE_OR_CODENAME lint error (requires API 30, min is 29)
- Mark technical check strings as translatable="false"
- Add Android lint step to CI
- Apply ktlint formatting
- Remove CheckRunnerService and :checks process — the ECONNREFUSED
issue was caused by Android per-app network restriction, not Vector
runtime. Checks run directly in the main process now.
- Delete test-app entirely — all diagnostics are now in the VPN Hide app
- Remove test-app from CI, lint, .gitignore, and update-version.sh
- Add lsposed/native to version update script and CI lint
- Add signingConfigs to both build.gradle.kts files, reading keystore
credentials from keystore.properties (gitignored, local absolute path)
- Both debug and release builds use the same signing key for consistent
signatures between local and CI builds
- CI decodes keystore from ANDROID_KEYSTORE_BASE64 secret, builds
assembleRelease instead of assembleDebug
- Add keystore-related files to .gitignore for test-app
- Rename lint-rust → lint, add clang-format and ktlint checks
- Add cargo test step for zygisk unit tests
- Install clang-format and ktlint 1.8.0 in CI Docker image
Replace custom kernel source cloning + prepare with pre-built DDK
Docker images (ghcr.io/ylarod/ddk-min). These include kernel headers,
Module.symvers, and AOSP clang for each GKI generation.
Now builds for: android12-5.10, android13-5.10, android13-5.15,
android14-5.15, android14-6.1, android15-6.6, android16-6.12.
Drop sha256 files from releases.
Port all 15 native VPN detection checks from C++ to Rust using
jni + libc crates. Gradle triggers cargo-ndk automatically via
a preBuild dependency — single `./gradlew installDebug` builds
everything.
- Remove CMakeLists.txt and native-lib.cpp
- Add test-app/native/ Rust crate with Cargo.toml and src/lib.rs
- Gradle buildRustNative task runs cargo-ndk, copies .so to jniLibs
- Update CI test-app job with Rust + NDK setup
- 23/23 checks pass on device
Replace separate kmod/zygisk/lsposed workflows with one ci.yml.
Four jobs run in parallel: kmod, zygisk, lsposed, test-app.
A release job depends on all four and runs only on tag pushes,
creating a GitHub release with all artifacts and checksums.
- Add Google's AOSP clang (clang-r487747c, same as Pixel kernel build)
to the CI Docker image via sparse checkout. Distro clang caused ABI
mismatches leading to bootloops on device.
- Update kmod workflow to use the Docker image + AOSP clang instead of
system clang from apt.
- Replace symvers with real vmlinux.symvers from Pixel kernel build
(8050 symbols vs 4060 from device .ko extraction).
- Add kmod build deps (bc, kmod, cpio, binutils-aarch64) to Docker image.
Unified repository for the complete Android VPN-hiding stack:
- zygisk/ — Rust Zygisk module (inline libc hooks via shadowhook)
- lsposed/ — Kotlin LSPosed module (Java API + system_server hooks)
- kmod/ — C kernel module (kretprobe hooks, invisible to anti-tamper)
CI workflows use path filters to build only the changed component.