Skip to content

fix: require Okio 3.11.0 to prevent gzip corruption - #831

Open
dustinbyrne wants to merge 3 commits into
mainfrom
fix/okio-minimum-3.11.0
Open

dustinbyrne wants to merge 3 commits into
mainfrom
fix/okio-minimum-3.11.0

Conversation

@dustinbyrne

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

Require Okio 3.11.0 or later so gzip request compression includes the fix for Okio #1608.

Older Okio versions can recycle a compression input buffer while Deflater still retains its reference. When Android's JNI layer copies arrays, a later flush can overwrite compressed output with stale input. This can produce invalid /flags and /batch request bodies before transmission. Okio 3.11.0 clears the retained reference.

  • Declare Okio directly in core as a normal implementation dependency; newer compatible versions can still resolve.
  • Refresh dependency locks, including the compliance adapter.
  • Add small/large request round-trip coverage for multiple writes and flushes, gzip headers, content type, and content length.
  • Add patch changesets for core, Android, and server so consumers receive the fixed dependency.

Compatibility

The Kotlin language/API compatibility target remains 2.0, and the Java bytecode target remains Java 8. A Kotlin 2.0.0 Android consumer of the locally published artifact builds successfully, including a minified release APK.

Okio 3.11.0 contains Kotlin 2.1 metadata. Kotlin 1.9 projects that currently work by overriding the standard library can fail if Okio appears on their compile classpath. Current PostHog already resolves Kotlin stdlib 2.1.21; this does not raise the configured Kotlin 2.0 floor, but those older override configurations are not compatibility-neutral.

💚 How did you test it?

  • ./gradlew :posthog:test --tests com.posthog.internal.GzipRequestInterceptorTest --tests com.posthog.internal.PostHogApiTest
  • Full repository build plus :posthog-android-gradle-plugin:build; final pass excluded the sample's mapping-upload task.
  • make checkFormat
  • make checkRelease with an isolated local Maven repository; committed locks remain unchanged.
  • Compliance adapter installDist with its normally Docker-included project enabled through a temporary init script.
  • Inspected generated Gradle metadata (requires: 3.11.0) and Maven runtime dependency (okio-jvm:3.11.0).
  • Kotlin 2.0.0 / AGP 8.9.1 consumer compiled and built an R8-minified release APK against this branch's locally published core artifact; compile/runtime both resolve Okio 3.11.0.

Prior controlled Android 16 reproduction used app_process -Xcheck:jni -Xjniopts:forcecopy: with core 6.43.0, Okio 3.9.1 failed all 80 flags/batch compression checks per run, while 3.11.0 passed. Three runs per version agreed. Java gzip controls passed. This demonstrates the upstream mechanism; it does not establish why a particular managed device triggers equivalent behavior. The checked-in JVM test is round-trip coverage, not a forced-JNI reproduction.

📝 Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Implemented with Pi using local Gradle/Android builds and GitHub CLI. A fresh read-only reviewer inspected the diff and found no issues. Human review is required before merge.

@dustinbyrne dustinbyrne self-assigned this Oct 2, 2026
@greptile-apps

greptile-apps Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Retrigger

[High risk] Upgrades a core compression dependency across all modules.

The PR appears safe to merge; no new actionable issue was identified.

Reviews (2) · Last reviewed commit: "chore: include surveys compose in Okio f..."

@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

posthog-android Compliance Report

Date: 2026-10-02 17:15:00 UTC
Duration: 118434ms

✅ All Tests Passed!

46/46 tests passed


Capture Tests

✅ 29/29 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 379ms
Format Validation.Event Has Uuid ✅ 39ms
Format Validation.Event Has Lib Properties ✅ 32ms
Format Validation.Distinct Id Is String ✅ 31ms
Format Validation.Token Is Present ✅ 33ms
Format Validation.Custom Properties Preserved ✅ 26ms
Format Validation.Event Has Timestamp ✅ 24ms
Retry Behavior.Retries On 503 ✅ 7028ms
Retry Behavior.Does Not Retry On 400 ✅ 4026ms
Retry Behavior.Does Not Retry On 401 ✅ 4025ms
Retry Behavior.Respects Retry After Header ✅ 7026ms
Retry Behavior.Implements Backoff ✅ 17035ms
Retry Behavior.Retries On 500 ✅ 7019ms
Retry Behavior.Retries On 502 ✅ 7019ms
Retry Behavior.Retries On 504 ✅ 7018ms
Retry Behavior.Max Retries Respected ✅ 17020ms
Deduplication.Generates Unique Uuids ✅ 38ms
Deduplication.Preserves Uuid On Retry ✅ 7016ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 12031ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 7018ms
Deduplication.No Duplicate Events In Batch ✅ 35ms
Deduplication.Different Events Have Different Uuids ✅ 28ms
Compression.Sends Gzip When Enabled ✅ 18ms
Batch Format.Uses Proper Batch Structure ✅ 20ms
Batch Format.Flush With No Events Sends Nothing ✅ 13ms
Batch Format.Multiple Events Batched Together ✅ 36ms
Error Handling.Does Not Retry On 403 ✅ 4026ms
Error Handling.Does Not Retry On 413 ✅ 4020ms
Error Handling.Retries On 408 ✅ 5030ms

Feature_Flags Tests

✅ 17/17 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 33ms
Request Payload.Flags Request Uses V2 Query Param ✅ 23ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 20ms
Request Payload.Flags Request Omits Authorization Header ✅ 26ms
Request Payload.Token In Flags Body Matches Init ✅ 20ms
Request Payload.Groups Round Trip ✅ 24ms
Request Payload.Groups Default To Empty Object ✅ 25ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 29ms
Request Payload.Disable Geoip Omitted Defaults To False ✅ 26ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 22ms
Request Lifecycle.No Flags Request On Init Alone ✅ 22ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 20ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 38ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 20ms
Retry Behavior.Retries Flags On 502 ✅ 323ms
Retry Behavior.Retries Flags On 504 ✅ 323ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 21ms

@dustinbyrne
dustinbyrne marked this pull request as ready for review October 2, 2026 17:08
@dustinbyrne
dustinbyrne requested a review from a team as a code owner October 2, 2026 17:08
@dustinbyrne

Copy link
Copy Markdown
Contributor Author

One compatibility note: this can break Kotlin 1.9 projects that currently work by overriding the Kotlin standard library, if Okio is exposed on their compile classpath. Okio 3.11.0 carries Kotlin 2.1 metadata, which the 1.9 compiler cannot read.

Our existing configured compatibility target is already Kotlin 2.0:

kotlinVersion=2.1.21
kotlinCompatibility=2.0

These settings predate this PR: gradle.properties. The shared compiler configuration applies that target to both languageVersion and apiVersion.

The bump therefore preserves the configured Kotlin 2.0 target, but not every previously working Kotlin 1.9 override configuration. A Kotlin 2.0.0 Android consumer of this branch’s published artifact passed compilation and an R8-minified release build.

@marandaneto

Copy link
Copy Markdown
Member

Should we bump min. Okhttp then that depends on okio min 3.11? This could cause incompatibilities i think, okio is a transitive dep

@dustinbyrne

Copy link
Copy Markdown
Contributor Author

i believe it's okay

OkHttp 4.12.0 declares a normal Okio 3.6.0 requirement, not a strict pin, so Gradle can resolve 3.11.0. We also use Okio directly in the SDK. I tested this combination through the SDK suite and an Android consumer build. Since 4.12.0 is the latest 4.x, upgrading OkHttp would mean taking on a 5.x upgrade;

# This file is expected to be part of source control.
# To regenerate this file, run: ./gradlew :posthog-android:dependencies --write-locks
androidx.activity:activity-compose:1.13.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath
androidx.activity:activity-compose:1.13.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath,testImplementationDependenciesMetadata

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.

[question] Most of the churn in this file is testImplementationDependenciesMetadata moving between entries, which doesn't look Okio-related. Was it from regenerating locks in a different setup, or expected?

This branch has not been deployed

No deployments
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.

4 participants