Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/codeql/codeql-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: kuri CodeQL config

# SAST-first. security-and-quality is a superset of security-extended, so this runs CodeQL's full
# security query set (injection / SSRF / path-traversal / unsafe-parsing / crypto / etc. — the ones
# that matter for a URL/URI library that turns untrusted text into hosts, paths and queries) plus
# its reliability and maintainability queries. Security is the goal; the quality queries are the
# "whatever else it provides".
queries:
- uses: security-and-quality

# The IDNA/UTS-46 mapping + validity tables and the NFC table are machine-generated from the Unicode
# UCD (thousands of entries, regenerated by the codegen tasks, never hand-edited). Findings in them
# are noise, not defects, so keep them out of the alert list and focus scanning on hand-written code.
paths-ignore:
- '**/idna/IdnaMappingTableData.kt'
- '**/idna/IdnaValidityData.kt'
- '**/idna/NfcData.kt'
86 changes: 83 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,32 @@ jobs:
distribution: corretto
java-version: '21'
- uses: gradle/actions/setup-gradle@v4
# Restore the Kotlin/Native toolchain (~1 GB: compiler bundle + LLVM/sysroot/gcc deps under
# ~/.konan). setup-gradle caches ~/.gradle but not ~/.konan, and apiCheck's KLIB ABI validation
# compiles every native klib here, so without this the whole bundle re-downloads each run.
# The key is scoped `-gate-` (the native job below uses `-native-`) so the two Linux jobs each
# cache the toolchain subset they actually pull and never race to write one shared key on main.
# Restore runs on every branch (PRs reuse main's cache); only main writes it (see the save step
# below). The key tracks the version catalog; restore-keys give a partial hit when it changes.
- name: Restore Kotlin/Native toolchain
id: konan-cache
uses: actions/cache/restore@v4
with:
path: ~/.konan
key: ${{ runner.os }}-konan-gate-${{ hashFiles('gradle/libs.versions.toml') }}
restore-keys: ${{ runner.os }}-konan-gate-
- name: ktlint, detekt, binary-compatibility and JVM coverage floor
# koverVerify pulls in jvmTest and enforces the 80% line-coverage rule.
run: ./gradlew ktlintCheck detekt apiCheck jvmTest koverVerify --stacktrace
# Write the toolchain cache only from main, and only when the restore was not an exact hit
# (GitHub caches are write-once per key). PRs never write, so parallel branches can't evict
# main's warm cache.
- name: Save Kotlin/Native toolchain
if: github.ref == 'refs/heads/main' && steps.konan-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: ~/.konan
key: ${{ runner.os }}-konan-gate-${{ hashFiles('gradle/libs.versions.toml') }}

web:
name: JS · Wasm tests (Linux x64)
Expand Down Expand Up @@ -117,8 +140,27 @@ jobs:
distribution: corretto
java-version: '21'
- uses: gradle/actions/setup-gradle@v4
# Restore the Kotlin/Native toolchain (~1 GB under ~/.konan) that this native job compiles and
# links against; setup-gradle caches ~/.gradle but not ~/.konan. runner.os in the key keeps the
# Linux/Windows/macOS legs separate, and the `-native-` scope keeps the Linux leg from colliding
# with the quality-gate job's `-gate-` cache. Restore runs on every branch; only main writes it.
- name: Restore Kotlin/Native toolchain
id: konan-cache
uses: actions/cache/restore@v4
with:
path: ~/.konan
key: ${{ runner.os }}-konan-native-${{ hashFiles('gradle/libs.versions.toml') }}
restore-keys: ${{ runner.os }}-konan-native-
- name: ${{ matrix.name }}
run: ./gradlew ${{ matrix.tasks }} --stacktrace
# Write the toolchain cache only from main, and only on a non-exact restore (caches are
# write-once per key), so PR legs never evict main's warm per-OS cache.
- name: Save Kotlin/Native toolchain
if: github.ref == 'refs/heads/main' && steps.konan-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: ~/.konan
key: ${{ runner.os }}-konan-native-${{ hashFiles('gradle/libs.versions.toml') }}

android-unit:
name: Android unit tests (Linux x64)
Expand All @@ -131,8 +173,6 @@ jobs:
with:
distribution: corretto
java-version: '21'
# AGP needs an Android SDK at configuration time; this installs it and accepts licenses.
- uses: android-actions/setup-android@v3
- uses: gradle/actions/setup-gradle@v4
- name: Android host (JVM) unit tests
# Runs commonTest compiled for the Android target on the JVM — no emulator.
Expand All @@ -157,17 +197,57 @@ jobs:
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
# Restore the cached AVD (system image, created device, boot snapshot) under ~/.android so a run
# can skip the image download, AVD creation and cold boot and load a warm snapshot instead.
# Restore runs on every branch (PRs reuse main's snapshot); only main writes it (see save below).
# The key pins every coordinate that affects the snapshot; bump the -v suffix if the emulator
# options change, since GitHub caches are write-once per key.
- name: Restore AVD snapshot
id: avd-cache
uses: actions/cache/restore@v4
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-30-aosp_atd-x86_64-pixel6-v1
# On main with no cached snapshot, boot once to create the AVD and write a clean boot snapshot
# for the cache. Emulator options match the test run so the snapshot stays valid. Gated to main
# because only main persists it — PRs skip this create-and-snapshot step and run the test step
# below once, warm-booting from main's cached snapshot when present (a single boot, not two).
- name: Create AVD and generate snapshot for caching
if: github.ref == 'refs/heads/main' && steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 30
target: aosp_atd
arch: x86_64
profile: pixel_6
force-avd-creation: false
disable-animations: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
script: echo "Generated AVD snapshot for caching."
- name: Android instrumented tests on an emulator
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 30
target: aosp_atd
arch: x86_64
profile: pixel_6
force-avd-creation: false
disable-animations: true
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
# -no-snapshot-save: boot from the cached snapshot but don't rewrite it on exit.
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -no-snapshot-save -camera-back none
# Installs and runs the androidDeviceTest instrumentation (an ART smoke test) on the emulator.
script: ./gradlew :kuri:connectedAndroidDeviceTest --stacktrace
# Persist the AVD snapshot for later runs — only from main, and only on a non-exact restore.
- name: Save AVD snapshot
if: github.ref == 'refs/heads/main' && steps.avd-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-30-aosp_atd-x86_64-pixel6-v1

# Aggregate gate: a single check to require in branch protection. Green only when every
# job above succeeded; fails if any was skipped, cancelled or failed.
Expand Down
83 changes: 83 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: CodeQL

# CodeQL SAST (static application security testing) for the JVM (Java + Kotlin) surface of kuri,
# plus CodeQL's reliability/maintainability queries — the query suite is set to security-and-quality
# in .github/codeql/codeql-config.yml. CodeQL only extracts JVM-bytecode-producing compilation; in
# this KMP project all production code is common + jvm Kotlin (the whole parsing engine lives in
# commonMain, and the reflective binder in kuri-bind's jvmMain), which the JVM target compiles, so a
# single traced JVM build covers commonMain + jvmMain — the entire security-relevant surface. Only
# platform-specific `actual` bodies (in jsMain/nativeMain/wasmJsMain, if any) fall outside this JVM
# extraction; CodeQL can't extract those targets, and they are covered by the CI test matrix instead.

on:
push:
branches: [ main ]
pull_request:
schedule:
# Weekly re-scan (Mondays 03:19 UTC) so newly published CodeQL queries flag issues even on a
# week with no code change. Off-the-hour to avoid the top-of-hour scheduling congestion.
- cron: '19 3 * * 1'

# A newer push to the same PR ref cancels an in-flight scan instead of stacking concurrent analyses;
# main runs are never cancelled, so every default-branch commit keeps its own recorded CodeQL result.
concurrency:
group: codeql-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

# Least privilege by default; the analyze job widens to what code-scanning upload needs.
permissions:
contents: read

jobs:
analyze:
name: Analyze (Java/Kotlin)
runs-on: ubuntu-latest
# A wedged extractor or build should fail fast rather than burn the 6-hour default.
timeout-minutes: 30
permissions:
# Upload the SARIF results to the repository's code-scanning alerts.
security-events: write
# Read workflow run metadata (required by CodeQL on private repos; harmless here).
actions: read
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
# Match the CI jobs: Gradle runs on Corretto 21 (the module's jvmToolchain(21)).
distribution: corretto
java-version: '21'
- uses: gradle/actions/setup-gradle@v4

# Initialise the CodeQL tracer BEFORE the build so the Kotlin/Java compilation is extracted.
# 'java' is CodeQL's identifier for the Java/Kotlin extractor (it analyses Kotlin too).
# Pinned to the codeql-action's current major (@v4 → latest 4.x), matching how every other
# action here is pinned by major tag. The action version and the CodeQL CLI *bundle* version are
# separate schemes: @v4 selects the action, which ships a recent CLI bundle (2.26.x) on its own.
# (The previous @v2.26.0 pinned the long-deprecated v2 *action* — not the 2.26.0 CLI bundle it
# was mistaken for.)
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: java
# v4's explicit mode for a compiled language whose database is built by manual commands
# between init and analyze (the `compileKotlinJvm` step below), never by autobuild — which
# would build the whole KMP project. Omitting it works too (the tracer path is identical for
# Java), but declaring it self-documents that autobuild is deliberately avoided.
build-mode: manual
# security-and-quality query suite + generated-code exclusions.
config-file: ./.github/codeql/codeql-config.yml

# Manual traced build instead of autobuild: compile only the JVM target of every module
# (compileKotlinJvm runs in :kuri and :kuri-bind). Autobuild would run the whole KMP build,
# including the native/JS/Wasm targets CodeQL can't extract. --no-build-cache forces a real
# compile (the project has the Gradle build cache on, which would otherwise serve cached
# classes and leave the tracer nothing to see); --no-daemon keeps compilation in the traced
# build process rather than a pre-existing untraced daemon.
- name: Compile JVM sources for CodeQL
run: ./gradlew compileKotlinJvm --no-daemon --no-build-cache --stacktrace

- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@v4
with:
category: "/language:java"
4 changes: 4 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8
org.gradle.caching=true
org.gradle.configuration-cache=true
kotlin.mpp.stability.nowarn=true
# Native tasks for targets that can't run on the current CI host (e.g. iosSimulator on Linux) are
# disabled by Kotlin and emit a warning each; this silences that wall of warnings without changing
# what builds. Cross-compiled klib/*TestBinaries build breaks are still caught by the native jobs.
kotlin.native.ignoreDisabledTargets=true
android.useAndroidX=true

# Dokka 2.x runs in V1 (deprecated) mode unless the V2 plugin is opted into; V2 provides the
Expand Down
Loading
Loading