Skip to content

ci: cache the Kotlin/Native toolchain and Android AVD, enforce native ABI, add CodeQL#60

Open
OmarAlJarrah wants to merge 4 commits into
mainfrom
ci/speed-up-cache-konan-avd-and-enforce-klib-abi
Open

ci: cache the Kotlin/Native toolchain and Android AVD, enforce native ABI, add CodeQL#60
OmarAlJarrah wants to merge 4 commits into
mainfrom
ci/speed-up-cache-konan-avd-and-enforce-klib-abi

Conversation

@OmarAlJarrah

@OmarAlJarrah OmarAlJarrah commented Jul 10, 2026

Copy link
Copy Markdown
Member

Why

CI wall-clock was dominated by work that either ran every time or ran for nothing:

  • The JVM "quality gate" job downloaded the whole Kotlin/Native toolchain. apiCheck
    pulls 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.
  • ~/.konan was never cached. gradle/actions/setup-gradle caches ~/.gradle but not
    ~/.konan, so the JVM job and all three native legs re-downloaded the toolchain on every run.
  • The emulator job recreated its AVD and re-downloaded the system image each run.
  • The Android unit job re-downloaded the command-line tools even though the runner ships
    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).
apiCheck now diffs the native public API on every run, so a source-compatible but
ABI-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. ~/.konan is cached on the JVM and
native 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-android from the host-unit job (the runner's
preinstalled SDK covers compileSdk 35), and set kotlin.native.ignoreDisabledTargets=true to
silence the wall of "Native task X is disabled" warnings that cluttered every job's log.

Add CodeQL (SAST). A new codeql.yml runs CodeQL on pushes to main, pull requests, and a
weekly schedule, with the security-and-quality query suite (the full security/SAST query set
plus CodeQL's reliability and maintainability queries). Since this is a KMP project with all
production code in commonMain + jvmMain Kotlin, a single manual traced build of the JVM
target 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

  • The kuri/api/kuri.klib.api dump is generated on macOS but validated on the Linux apiCheck
    runner; the public API is fully common across targets, so the merged ABI is identical on both
    hosts. Confirmed green on this branch's first CI run.
  • Dropping setup-android couples the host-unit job to the runner image's Android contents; it's
    preinstalled today, but a future image change would need it restored. Confirmed green here.
  • CodeQL runs on github/codeql-action@v4 — the current major, which bundles the CodeQL 2.26.x
    CLI. (The 2.26.0 in codeql-bundle-v2.26.0 is that CLI bundle version, not an action version;
    the earlier @v2.26.0 had pinned the v2 action major, retired in January 2025.) build-mode: manual makes the traced compileKotlinJvm build the database source, so autobuild never runs
    the full KMP build. Analysis covers the JVM (Java/Kotlin) surface — commonMain + jvmMain,
    i.e. the whole engine plus the reflective binder; only platform-specific actual bodies fall
    outside it, and those targets are covered by the test matrix. Confirmed green: an empty database
    would have failed the analyze step, and it passed.

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.
@github-advanced-security

Copy link
Copy Markdown

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:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

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.
@OmarAlJarrah OmarAlJarrah force-pushed the ci/speed-up-cache-konan-avd-and-enforce-klib-abi branch from dc1a797 to d7e734a Compare July 11, 2026 00:03
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants