ci: cache the Kotlin/Native toolchain and Android AVD, enforce native ABI, add CodeQL#60
Merged
OmarAlJarrah merged 6 commits intoJul 13, 2026
Conversation
binary-compatibility-validator's KLIB ABI validation is experimental and off by default, so apiCheck already compiled every native klib but then skipped the comparison -- the native public API was never actually gated. Enable it and commit the merged api/kuri.klib.api snapshot, so a source-compatible but ABI-breaking change to the native surface now fails the build alongside the existing JVM and Android ABI checks.
The JVM quality-gate and native matrix jobs re-downloaded the ~1 GB Kotlin/Native toolchain (compiler + LLVM/sysroot) on every run, because setup-gradle caches ~/.gradle but not ~/.konan; the emulator job recreated its AVD and re-downloaded the system image each time; and the Android unit job re-downloaded the command-line tools despite a preinstalled SDK. Cache ~/.konan and the AVD snapshot, restoring on every branch but writing only from main so pull requests stay fast without evicting main's cache. Drop android-actions/setup-android from the host-unit job (the runner's preinstalled SDK covers compileSdk 35) and silence the disabled-native-target warnings that cluttered every job's log.
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
Scan the JVM (Java + Kotlin) compilation with CodeQL on pushes to main, pull requests, and a weekly schedule, using the security-and-quality query suite so it runs the full security (SAST) query set plus CodeQL's reliability and maintainability queries. In this KMP project all production code is common + jvm Kotlin, so a manual traced build of the JVM target (compileKotlinJvm) covers the whole analysable surface -- autobuild is avoided because CodeQL cannot extract the native/JS/Wasm targets. The machine-generated Unicode lookup tables are excluded from results to keep the alert list focused on hand-written code.
dc1a797 to
d7e734a
Compare
Follow-ups to the CI hardening in this branch: - CodeQL: bump github/codeql-action from @v2.26.0 to @v4 on both init and analyze. 2.26.0 is the CodeQL CLI bundle version (codeql-bundle-v2.26.0), not an action version; @v2.26.0 pinned the v2 action major, retired in January 2025. @v4 is the current major (v3 deprecates December 2026) and ships the 2.26.x CLI bundle itself. Declare build-mode: manual so the traced compileKotlinJvm build is the explicit database source and autobuild (which would build the whole KMP project) is never used. - CodeQL: add a concurrency group so a new push to a PR cancels its in-flight scan while main runs still finish, and note in the header that platform actuals (js/native/wasm) fall outside the JVM extraction. - Scope the ~/.konan cache keys per job (-gate- for the quality gate, -native- for the native matrix) so the two Linux jobs no longer race to write one shared key on main and each caches the toolchain subset it pulls. - Reword the AVD snapshot comment: PRs warm-boot from main's cached snapshot (a single boot), they do not cold-boot.
Pin reactivecircus/android-emulator-runner to a commit SHA (v2.38.0) on both uses so a moved tag can't change what runs during emulator boot; GitHub-owned actions stay on major tags. Correct the CI comments to match what the build actually does: the two Linux Konan caches are scoped separately because the quality-gate job cross-builds the mingw klib for the ABI dump while the native leg does not, so they populate different ~/.konan subsets; and the AVD cache holds the created device and boot snapshot only, not the system-image package (sdkmanager still installs that). Document that KLIB ABI enforcement compares only the targets buildable on the apiCheck host — on the Linux gate the Apple targets are inferred from the merged dump, not re-verified — and note in CLAUDE.md that the kuri.klib.api dump must be regenerated on macOS or the Apple targets are silently dropped. Drop the redundant literal prefix from the CodeQL concurrency group.
The KLIB ABI check runs on the Linux quality-gate host, which can build the linuxX64/linuxArm64/mingw/js/wasm klibs but not the Apple ones, so it infers the Apple targets from the merged dump instead of re-verifying them. An Apple-target ABI break — or a dump regenerated on a non-macOS host, which silently drops the Apple targets from the merged header — would therefore pass CI unnoticed. Run klibApiCheck on the macOS native leg, the one host that can build every klib target, so the Apple ABI is verified for real rather than inferred. Update the build-script and CLAUDE.md notes to describe the host split, and complete the commit-prefix list to match .github/scripts/check-conventional-commit.sh.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
CI wall-clock was dominated by work that either ran every time or ran for nothing:
apiCheckpulls binary-compatibility-validator's KLIB ABI validation, which compiles all 11 native
klibs — but that validation is experimental and off by default, so it compiled the klibs
and then skipped the comparison. The job downloaded ~1 GB of compiler + LLVM and built
every native target to enforce nothing.
~/.konanwas never cached.gradle/actions/setup-gradlecaches~/.gradlebut not~/.konan, so the JVM job and all three native legs re-downloaded the toolchain on every run.a preinstalled SDK.
What changed
Enforce the native ABI (turn the wasted work into real coverage). Enable KLIB ABI
validation and commit
kuri/api/kuri.klib.api(the merged dump across all 13 klib targets).apiChecknow diffs the native public API on every run, so a source-compatible butABI-breaking change to the native surface fails the build — the same guarantee the JVM and
Android dumps already give. The native compilation the job was doing anyway now means something.
Cache the Kotlin/Native toolchain and the Android AVD.
~/.konanis cached on the JVM andnative jobs; the emulator's AVD snapshot is cached on the instrumented job. Both use
restore-on-every-branch / save-only-from-main, so pull requests boot from main's warm cache but
never write their own — keeping the shared cache from thrashing under the per-repo size limit.
Trim the rest. Drop
android-actions/setup-androidfrom the host-unit job (the runner'spreinstalled SDK covers
compileSdk 35), and setkotlin.native.ignoreDisabledTargets=truetosilence the wall of "Native task X is disabled" warnings that cluttered every job's log.
Add CodeQL (SAST). A new
codeql.ymlruns CodeQL on pushes to main, pull requests, and aweekly schedule, with the
security-and-qualityquery suite (the full security/SAST query setplus CodeQL's reliability and maintainability queries). Since this is a KMP project with all
production code in
commonMain+jvmMainKotlin, a single manual traced build of the JVMtarget covers the entire analysable surface — autobuild is avoided because CodeQL can't extract
the native/JS/Wasm targets. The machine-generated Unicode lookup tables are excluded from results.
Notes
kuri/api/kuri.klib.apidump is generated on macOS.apiCheckon the Linux quality-gaterunner re-verifies the non-Apple klib targets (linuxX64/linuxArm64/mingwX64/js/wasmJs); the macOS
nativeleg runsklibApiCheck, which builds every klib target and re-verifies the Apple targets(macos/ios/tvos/watchos) the Linux host can only infer. Every klib target's ABI is checked on a host
that can build it, and a dump regenerated off-macOS — which silently drops the Apple targets — fails
the macOS check. Confirmed green on CI.
setup-androidcouples the host-unit job to the runner image's Android contents; it'spreinstalled today, but a future image change would need it restored. Confirmed green here.
github/codeql-action@v4— the current major, which bundles the CodeQL 2.26.xCLI. (The
2.26.0incodeql-bundle-v2.26.0is that CLI bundle version, not an action version;the earlier
@v2.26.0had pinned the v2 action major, retired in January 2025.)build-mode: manualmakes the tracedcompileKotlinJvmbuild the database source, so autobuild never runsthe full KMP build. Analysis covers the JVM (Java/Kotlin) surface —
commonMain+jvmMain,i.e. the whole engine plus the reflective binder; only platform-specific
actualbodies falloutside it, and those targets are covered by the test matrix. Confirmed green: an empty database
would have failed the analyze step, and it passed.