Skip to content

fix(kotlin): verify native download checksums#508

Open
shubhamsinnh wants to merge 2 commits into
RunanywhereAI:mainfrom
shubhamsinnh:codex/issue-210-kotlin-native-download-checks
Open

fix(kotlin): verify native download checksums#508
shubhamsinnh wants to merge 2 commits into
RunanywhereAI:mainfrom
shubhamsinnh:codex/issue-210-kotlin-native-download-checks

Conversation

@shubhamsinnh

@shubhamsinnh shubhamsinnh commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Fixes #210

Summary

  • Add a shared Kotlin Gradle helper for native zip downloads.
  • Use HttpURLConnection with a 30s connect timeout and 120s read timeout.
  • Fetch .sha256 sidecar files and verify downloaded zips before extraction.
  • Fail native download tasks on failed download or checksum mismatch instead of warning and continuing.
  • Publish Android backend zip .sha256 files from the release workflow for LlamaCPP and ONNX backend artifacts.

Context

A previous PR, #416, attempted this issue but was closed unmerged. One blocker noted there was that backend .sha256 files did not exist on GitHub Releases, so checksum verification could not run end-to-end. This PR includes the release packaging changes needed for future releases to publish those backend checksum sidecars.

Testing

Passed locally:

  • git diff --check
  • bash -n sdk/runanywhere-commons/scripts/build-android.sh
  • ./gradlew.bat buildSrc:build --no-daemon --console=plain
  • ./gradlew.bat help --no-daemon --stacktrace --console=plain
  • ./gradlew.bat test --no-daemon --console=plain -Prunanywhere.useLocalNatives=false -x downloadJniLibs -x :modules:runanywhere-core-llamacpp:downloadJniLibs -x :modules:runanywhere-core-onnx:downloadJniLibs
  • ./gradlew.bat lint --no-daemon --console=plain -Prunanywhere.useLocalNatives=false -x downloadJniLibs -x :modules:runanywhere-core-llamacpp:downloadJniLibs -x :modules:runanywhere-core-onnx:downloadJniLibs
  • ./gradlew.bat check --no-daemon --console=plain -Prunanywhere.useLocalNatives=false -x downloadJniLibs -x :modules:runanywhere-core-llamacpp:downloadJniLibs -x :modules:runanywhere-core-onnx:downloadJniLibs -x ktlintCheck -x ktlintMainSourceSetCheck

Known blockers observed locally:

  • Full remote-native check correctly fails against the current v0.19.13 release because RABackendLLAMACPP-android-arm64-v8a-v0.19.13.zip.sha256 returns HTTP 404. This PR fixes the release workflow for future releases, but cannot retroactively add sidecars to old releases.
  • Full unmodified check currently fails on unrelated ktlint violations in VoiceAgentMicDriver.kt and RunAnywhere.kt, which are outside this PR's scope.
  • Local-native mode on Windows fails in existing code with Unsupported host for Android NDK runtime lookup: Windows 10.

Note

Medium Risk
Builds now hard-fail on bad or unverifiable native downloads, and release/Android packaging must produce new backend artifacts; supply-chain behavior changes but does not touch runtime auth or app logic.

Overview
Kotlin Gradle native fetch now verifies release zips before extraction: a shared NativeLibraryDownload helper (in buildSrc) downloads each .zip.sha256 sidecar, compares SHA-256, uses HTTP timeouts, and fails the build on HTTP/checksum errors instead of logging a warning. The root SDK and LlamaCPP/ONNX modules all use this path for downloadJniLibs.

Android release packaging now emits per-ABI RABackendLLAMACPP-android-* and RABackendONNX-android-* archives (plus checksums) from build-android.sh, and the release workflow uploads them and requires them in the publish manifest—so future tags ship the sidecars backend downloads need. Older releases without those .sha256 files will still break remote-native builds until a new release is cut.

Reviewed by Cursor Bugbot for commit c89be6c. Configure here.

Summary by CodeRabbit

  • New Features

    • Android releases now publish backend-specific ZIP artifacts for each ABI (LlamaCPP and ONNX), each accompanied by matching .sha256 checksum files.
  • Bug Fixes

    • Native JNI ZIP downloads now verify SHA-256 checksums and fail the build on download/validation errors, with clearer failure details and cleanup of partial files.
  • Chores

    • Release packaging/publishing checks were tightened to require the new backend ZIPs and their checksum sidecars.
    • Android build scripts were updated to generate backend ZIPs deterministically with checksums.

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 29a8a6f3-9808-4fac-b6a8-2c096f05795b

📥 Commits

Reviewing files that changed from the base of the PR and between 3d69032 and 8622e37.

📒 Files selected for processing (2)
  • .github/workflows/release.yml
  • sdk/runanywhere-commons/scripts/build-android.sh
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/release.yml
  • sdk/runanywhere-commons/scripts/build-android.sh

📝 Walkthrough

Walkthrough

Android release packaging now emits backend-specific ZIPs and checksum files, the release workflow requires them, and JNI download tasks use a shared helper to verify ZIP checksums before extraction.

Changes

Android backend release packaging and publish checks

Layer / File(s) Summary
Backend ZIP artifacts and publish checks
sdk/runanywhere-commons/scripts/build-android.sh, .github/workflows/release.yml
Adds backend-specific Android ZIP packaging with .sha256 sidecars, uploads the new artifacts, and asserts their presence before publishing.

Shared checksum-verified download utility and JNI migration

Layer / File(s) Summary
Shared checksum-verified download utility
sdk/runanywhere-kotlin/buildSrc/build.gradle.kts, sdk/runanywhere-kotlin/buildSrc/src/main/kotlin/com/runanywhere/gradle/NativeLibraryDownload.kt
Configures buildSrc for Kotlin DSL and adds NativeLibraryDownload for HTTP ZIP downloads with timeouts, checksum parsing, digest computation, and cleanup on failure.
JNI download tasks use verified ZIPs
sdk/runanywhere-kotlin/build.gradle.kts, sdk/runanywhere-kotlin/modules/runanywhere-core-llamacpp/build.gradle.kts, sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts
Migrates JNI download tasks to checksum-verified ZIP downloads and changes failures to cleanup plus GradleException.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GradleTask as downloadJniLibs task
  participant NativeLibraryDownload
  participant ReleaseServer as release ZIP host
  participant FileSystem as file system

  GradleTask->>NativeLibraryDownload: downloadZipWithChecksum(zipUrl, tempZip)
  NativeLibraryDownload->>ReleaseServer: GET zipUrl.sha256
  ReleaseServer-->>NativeLibraryDownload: checksum text
  NativeLibraryDownload->>ReleaseServer: GET zipUrl
  ReleaseServer-->>NativeLibraryDownload: zip bytes
  NativeLibraryDownload->>FileSystem: write tempZip
  NativeLibraryDownload->>FileSystem: compute SHA-256
  NativeLibraryDownload->>NativeLibraryDownload: compare checksums
  alt mismatch or HTTP error
    NativeLibraryDownload->>FileSystem: delete tempZip
    NativeLibraryDownload-->>GradleTask: throw GradleException
  else match
    NativeLibraryDownload-->>GradleTask: return success
  end
Loading

Suggested labels: kotlin-sdk

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: adding checksum verification for native downloads.
Description check ✅ Passed It covers the summary, context, and testing, though template sections like type of change, labels, and screenshots are not filled out.
Linked Issues check ✅ Passed The PR implements the requested timeouts, SHA256 verification, shared download logic, and release-sidecar publishing for the native download flow.
Out of Scope Changes check ✅ Passed The added buildSrc and release workflow changes support the checksum-download feature and do not appear unrelated.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release.yml:
- Around line 789-790: The assertions for Android LlamaCPP and ONNX backend
artifacts only validate ZIP file presence but omit checking for required
`.sha256` sidecar files. Add additional `assert_present` calls after the
existing assertions on lines 789-790 to validate the corresponding `.sha256`
files for both the LlamaCPP and ONNX backend artifacts, using the same glob
patterns but with `.sha256` appended to match files like
RABackendLLAMACPP-android-*-v*.zip.sha256 and
RABackendONNX-android-*-v*.zip.sha256.

In `@sdk/runanywhere-commons/scripts/build-android.sh`:
- Around line 114-116: The conditional check at lines 114-116 silently skips the
operation when extra_file is set but the file does not exist at
${STAGING}/jni/${extra_file}. Make extra_file mandatory by modifying the logic
so that if extra_file is non-empty (requested), the script fails with an error
message if the file is not found at the expected location, rather than silently
continuing. Only proceed with the cp command if the file exists, but exit the
script with an appropriate error if extra_file is set but missing.

In `@sdk/runanywhere-kotlin/modules/runanywhere-core-llamacpp/build.gradle.kts`:
- Line 220: When the download and verification fails and throws a
GradleException at line 220, the already-copied .so files from previous
successful ABIs remain on disk. On subsequent task runs, the existence check at
line 183 will find these partial files and skip the download entirely, leaving
the build in an inconsistent state. Before throwing the GradleException in the
failure path, clean up any .so files that were already copied during this task
execution so that the next retry starts from a clean state and properly
re-downloads all required ABIs.

In `@sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts`:
- Line 223: When a download fails for a specific ABI in the loop, the exception
at the GradleException throw statement leaves partial .so files in outputDir.
Before throwing the exception, clean up any incomplete files that were
downloaded for the current ABI iteration to prevent the early-exit check
(existingLibs > 0) from incorrectly skipping downloads on retry and using the
broken native library set. Ensure the cleanup happens in the catch block before
the GradleException is thrown.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e647cc76-5c66-43f9-86e2-3b994b3bd15c

📥 Commits

Reviewing files that changed from the base of the PR and between c272a1f and c89be6c.

📒 Files selected for processing (7)
  • .github/workflows/release.yml
  • sdk/runanywhere-commons/scripts/build-android.sh
  • sdk/runanywhere-kotlin/build.gradle.kts
  • sdk/runanywhere-kotlin/buildSrc/build.gradle.kts
  • sdk/runanywhere-kotlin/buildSrc/src/main/kotlin/com/runanywhere/gradle/NativeLibraryDownload.kt
  • sdk/runanywhere-kotlin/modules/runanywhere-core-llamacpp/build.gradle.kts
  • sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts

Comment thread .github/workflows/release.yml
Comment thread sdk/runanywhere-commons/scripts/build-android.sh Outdated
@shubhamsinnh shubhamsinnh force-pushed the codex/issue-210-kotlin-native-download-checks branch from b81c341 to 3d69032 Compare July 4, 2026 12:39
@shubhamsinnh

shubhamsinnh commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

Hi @shubhammalhotra28 - All 4 CodeRabbit review suggestions have been addressed in commit b81c341 (.sha256 sidecar validation in release.yml, mandatory extra_file check in build-android.sh, cleanup-on-failure for both backend build.gradle.kts modules).

Please let me know if anything else is needed before this can be merged.

@Siddhesh2377

Copy link
Copy Markdown
Collaborator

Let us review your changes
thanks :)

@shubhamsinnh shubhamsinnh force-pushed the codex/issue-210-kotlin-native-download-checks branch from 3d69032 to 8622e37 Compare July 10, 2026 14:49
@shubhamsinnh

shubhamsinnh commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Hi @shubhammalhotra28 @Siddhesh2377 - just following up on this.

CI is green now after the rebase. Please let me know if you want me to change anything when you get a chance.

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.

Add timeout and SHA256 checksum verification for native library downloads

2 participants