ci: pass build artifacts between jobs via upload/download-artifact#28
Conversation
Fixes the cross-job cache-poisoning vector properly. The build/APK job used to restore the libcore + sidecars caches produced by other jobs, so an untrusted pull_request run could populate a cache that a later trusted run restored. Now each producer job (libcore, sidecars) uploads its output as a workflow artifact, and the build job downloads them. Caches that remain are strictly job-local (libcore.aar in the libcore job, executableSo in the sidecars job, ~/.gradle in the build job) — each is produced and consumed within the same job, so there is no cross-job/cross-run cache trust boundary to poison. This also lets caches keep working on pull_request runs (no save-gating needed), since they are no longer the cross-job bus.
|
Warning Review limit reached
More reviews will be available in 1 hour, 30 minutes, and 41 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
Summary
Proper fix for the cross-job cache-poisoning vector (the follow-up tracked from #18/#27).
Problem
The
buildjobneeds:thelibcoreandsidecarsjobs and restored their caches to assemble the APK — using the cache as a cross-job artifact bus. That means an untrustedpull_requestrun could populate a cache key that a later trusted (push/main) run restores. Simply gatingsaveto non-PR events (attempted in #27) breaks the bus, because PR runs then can't pass artifacts between jobs at all.Fix
Use the right tool for each purpose:
libcore,sidecars) nowupload-artifacts its output (libcore.aar,executableSo); thebuildjobdownload-artifacts them. Artifacts are scoped to a single workflow run, so there's no cross-run trust boundary.actions/cachesteps are each produced and consumed within the same job (libcore.aar in libcore, executableSo in sidecars,~/.gradlein build). No job restores a cache another job wrote, so there's nothing to poison — and caches keep working on PR runs (no save-gating needed).Applied uniformly across build/ci/preview/release (the release
publishjob is unchanged).Verification
The real test is CI on this PR exercising the new artifact bus.
Greptile Summary
This PR replaces the cross-job
actions/cacheartifact bus withupload-artifact/download-artifact, fixing the cache-poisoning vector where a PR run could write a cache entry later consumed by a trusted push run. The change is applied uniformly across all four workflows.libcore,sidecars) now uploads its output viaupload-artifact(withif-no-files-found: errorfor early failure), and thebuildjob downloads them; artifacts are scoped to a single workflow run so no cross-run trust boundary exists.libcoreandsidecarsfor build speed; thebuildjob no longer restores any cache written by another job.-build,-ci,-preview,-release), and thebuild/preview/releaseworkflows'libcorecache keys remain shared (all areworkflow_dispatch/push-only, never triggered by PRs).Confidence Score: 5/5
The change is safe to merge; it removes the cross-job cache bus and replaces it with run-scoped artifacts without disrupting any build logic.
The upload/download artifact names match within each workflow, the download paths reconstruct the directory layout that the Gradle build and sidecar-verification step expect, if-no-files-found: error ensures a missing artifact surfaces as a job failure rather than a silent stale-file issue, and the residual within-job caches are content-addressed and never consumed across jobs. No functional regressions are apparent.
No files require special attention.
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant LC as libcore job participant SC as sidecars job participant AS as Artifact Store (run-scoped) participant BJ as build job LC->>LC: actions/cache restore (job-local) alt cache miss LC->>LC: Install Golang + ./run lib core end LC->>AS: "upload-artifact (libcore-aar-{workflow})" SC->>SC: actions/cache restore (job-local) alt cache miss SC->>SC: Build Mieru/Hysteria2/MDVPN/Naive end SC->>AS: "upload-artifact (sidecars-so-{workflow})" BJ->>AS: "download-artifact (libcore-aar-{workflow})" BJ->>AS: "download-artifact (sidecars-so-{workflow})" BJ->>BJ: Verify sidecar .so files BJ->>BJ: Gradle Build (APK) BJ->>AS: upload-artifact (final APK)%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant LC as libcore job participant SC as sidecars job participant AS as Artifact Store (run-scoped) participant BJ as build job LC->>LC: actions/cache restore (job-local) alt cache miss LC->>LC: Install Golang + ./run lib core end LC->>AS: "upload-artifact (libcore-aar-{workflow})" SC->>SC: actions/cache restore (job-local) alt cache miss SC->>SC: Build Mieru/Hysteria2/MDVPN/Naive end SC->>AS: "upload-artifact (sidecars-so-{workflow})" BJ->>AS: "download-artifact (libcore-aar-{workflow})" BJ->>AS: "download-artifact (sidecars-so-{workflow})" BJ->>BJ: Verify sidecar .so files BJ->>BJ: Gradle Build (APK) BJ->>AS: upload-artifact (final APK)Reviews (1): Last reviewed commit: "ci: pass build artifacts between jobs vi..." | Re-trigger Greptile