Skip to content

[Java] Embed Rust CLI runtime 4.3: NativeRuntimeLoader — native binary extraction and caching - #2175

Open
edburns with Copilot wants to merge 5 commits into
edburns/1917-java-embed-rust-cli-runtime-dd-3039924-agentic-run-02from
copilot/edburns1917-java-embed-rust-cli-runtime-dd-3039924
Open

[Java] Embed Rust CLI runtime 4.3: NativeRuntimeLoader — native binary extraction and caching#2175
edburns with Copilot wants to merge 5 commits into
edburns/1917-java-embed-rust-cli-runtime-dd-3039924-agentic-run-02from
copilot/edburns1917-java-embed-rust-cli-runtime-dd-3039924

Conversation

Copilot AI commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Implements task 4.3 of the Java in-process FFI transport: NativeRuntimeLoader, which locates runtime.node on the classpath, extracts it atomically to a versioned cache directory, and returns the filesystem path for JNA to load.

Changes

java/sdk/pom.xml

  • Adds <resources> block with <filtering>true</filtering> so Maven substitutes ${project.version} into the new properties resource at build time.

java/sdk/src/main/resources/copilot-runtime.properties (new)

  • Single-property file: version=${project.version}. Maven resource filtering writes the real version; NativeRuntimeLoader reads it at runtime, giving a stable cache key that works from a JAR and from IDE-run target/classes/.

java/sdk/src/main/java/com/github/copilot/ffi/NativeRuntimeLoader.java (new)

Resolution order:

  1. COPILOT_CLI_PATH — if set, checks for runtime.node alongside the CLI binary (same directory).
  2. Classpath resource native/<classifier>/runtime.node — extracted atomically to ~/.copilot/runtime-cache/<version>/<classifier>/runtime.node.

Extraction sequence follows the plan's resolved decisions:

  • Fast path: return immediately if the versioned cache entry is a regular, non-empty file.
  • Slow path: Files.createTempFile in the same directory (guarantees same filesystem) → Files.copyFileChannel.force(true)Files.move(ATOMIC_MOVE). If another process wins the race, accept the winner after the same regular/non-empty check. If the filesystem rejects ATOMIC_MOVE, fail with a clear IllegalStateException. Temp file is deleted in finally.
  • No executable bit set; no file locking; no startup hash; no cleanup of old versions.
  • Classifier-aware: resource path is native/<classifier>/runtime.node, making the loader safe in future uber-jar scenarios where all 8 platform resources coexist on the classpath.
// Public API — uses real env, user home, and current-platform classifier
Path runtimeNode = NativeRuntimeLoader.resolve();

// Package-private overload for testing — injects temp cache dir and URLClassLoader
Path runtimeNode = NativeRuntimeLoader.resolve(null, tempCacheBase, fakeLoader, "linux-x64", "1.2.3");

java/sdk/src/test/java/com/github/copilot/ffi/NativeRuntimeLoaderTest.java (new)

17 unit tests using @TempDir and URLClassLoader for classpath resource injection — no real runtime.node needed. Covers: version resource reading, COPILOT_CLI_PATH priority, extraction to correct versioned path, cache hit (no re-extraction), missing resource errors, content fidelity, classifier filtering, and concurrent extraction safety (8-thread race with CountDownLatch).

… and caching (task 4.3)

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>
Copilot AI changed the title [WIP] Create NativeRuntimeLoader class for native binary extraction and caching [Java] Embed Rust CLI runtime 4.3: NativeRuntimeLoader — native binary extraction and caching Jul 30, 2026
Copilot AI requested a review from edburns July 30, 2026 22:01

@edburns edburns left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@copilot Please fix the following issue-requirement gaps:

Resolution order does not match the task and plan

NativeRuntimeLoader.resolve() currently reads copilot-runtime.properties before checking COPILOT_CLI_PATH, and resolveFromCliPath() interprets that variable only as a CLI executable whose sibling may be runtime.node. The task's authoritative plan distinguishes three ordered sources: (1) COPILOT_CLI_PATH as the explicit runtime override, (2) native/<classifier>/runtime.node from the classpath, and (3) runtime.node alongside the bundled CLI. The current implementation collapses sources 1 and 3 and has no separate bundled-CLI fallback.

Fix: Implement and test all three distinct resolution steps in the stated order. Honor a valid explicit override before reading the version properties or performing platform/classpath work, so an override remains usable even when those resources are unavailable. Add tests proving the classpath source wins over the bundled-CLI sibling and that the bundled-CLI sibling is used only when the classpath resource is absent. Surface clear errors for invalid explicit paths rather than silently changing the requested source unless the plan explicitly requires fallback.

Atomic rename behavior is not directly tested

The issue explicitly requires an atomic rename behavior test. The concurrent extraction test exercises a race but does not prove the ATOMIC_MOVE option is used or that an unsupported atomic move produces the required clear failure and cleans up the caller's temp file.

Fix: Add a deterministic test seam around publication and tests for atomic publication/failure cleanup, while preserving Files.move(temp, cached, ATOMIC_MOVE) in production.

@edburns
edburns marked this pull request as ready for review July 30, 2026 22:13
@edburns
edburns requested a review from a team as a code owner July 30, 2026 22:13
Copilot AI review requested due to automatic review settings July 30, 2026 22:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds Java native runtime discovery and atomic extraction for the in-process FFI transport.

Changes:

  • Adds versioned runtime.node resolution and caching.
  • Configures Maven-filtered runtime version metadata.
  • Adds unit coverage for resolution, caching, and concurrency.
Show a summary per file
File Description
java/sdk/pom.xml Enables resource filtering.
copilot-runtime.properties Provides the SDK version cache key.
NativeRuntimeLoader.java Implements native runtime resolution and extraction.
NativeRuntimeLoaderTest.java Tests loader behavior and concurrency.

Review details

  • Files reviewed: 4/4 changed files
  • Comments generated: 6
  • Review effort level: Balanced

Comment thread java/sdk/src/main/java/com/github/copilot/ffi/NativeRuntimeLoader.java Outdated
Comment thread java/sdk/src/main/java/com/github/copilot/ffi/NativeRuntimeLoader.java Outdated
Comment thread java/sdk/src/main/java/com/github/copilot/ffi/NativeRuntimeLoader.java Outdated
@github-actions github-actions Bot mentioned this pull request Jul 30, 2026
…rder and add AtomicPublisher test seam

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

Copilot AI commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Please fix the following issue-requirement gaps:

Resolution order does not match the task and plan...

Fixed in commit fix(java): fix NativeRuntimeLoader to implement 3-source resolution order and add AtomicPublisher test seam.

Resolution order — The three distinct sources are now implemented in the required order:

  1. COPILOT_CLI_PATH as explicit runtime override (resolveFromExplicitPath): treated as the direct path to runtime.node itself, checked before any classpath/platform/version work. A non-blank value that doesn't refer to a regular, non-empty file throws IllegalStateException immediately with no silent fallback.
  2. Classpath resource native/<classifier>/runtime.node: extracted atomically to the versioned cache (unchanged logic).
  3. Bundled-CLI sibling: runtime.node alongside the bundled CLI binary directory — a findBundledCliDirectory() placeholder (returns null until task 4.x implements the embedded CLI) with a bundledCliDir parameter for test injection. Used only when the classpath resource is absent.

Tests added: explicitOverrideTakesPriorityOverClasspathExtraction, explicitOverrideThrowsImmediatelyWhenPathIsInvalid, bundledCliSiblingIsUsedWhenClasspathResourceAbsent, classpathResourceWinsOverBundledCliSibling, bundledCliSiblingIsIgnoredWhenRuntimeNodeMissing.

Atomic rename test seam — Added @FunctionalInterface AtomicPublisher (package-private) with DEFAULT_PUBLISHER using Files.move(temp, cached, ATOMIC_MOVE). Both extractToCache and resolve now accept an injectable AtomicPublisher. Three new tests:

  • defaultPublisherMovesSourceToTarget: proves the production publisher uses move semantics (source absent, target present) rather than copy.
  • extractionCleansUpTempFileWhenPublicationFails: injects a publisher throwing AtomicMoveNotSupportedException; verifies the captured temp path is deleted.
  • extractionCleansUpTempFileWhenPublisherThrowsIllegalStateException: injects a publisher that wraps AtomicMoveNotSupportedException as IllegalStateException (simulating DEFAULT_PUBLISHER's failure path); verifies the error message contains "atomic moves" and the temp file is deleted.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI requested a review from edburns July 30, 2026 22:30
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

Cross-SDK Consistency Review ✅

This PR adds NativeRuntimeLoader — an internal FFI helper that locates and extracts runtime.node from the classpath for JNA to load.

Finding: No cross-SDK consistency issues. This is purely Java-internal infrastructure. All other SDKs already have equivalent native runtime loading mechanisms:

SDK Native Runtime Loader
Node.js/TypeScript nodejs/src/ffiRuntimeHost.ts
Python python/copilot/_ffi_runtime_host.py
Go go/internal/ffihost/resolve.go
.NET dotnet/src/FfiRuntimeHost.cs
Rust rust/src/ffi.rs
Java java/sdk/src/main/java/com/github/copilot/ffi/NativeRuntimeLoader.java (this PR)

This PR brings Java to parity with the other SDKs on native runtime loading. No changes are needed in other language implementations.

Generated by SDK Consistency Review Agent for #2175 · sonnet46 19.2 AIC · ⌖ 5.38 AIC · ⊞ 6.6K ·

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.

[Java] Embed Rust CLI runtime 4.3: Native binary extraction and caching

3 participants