fix(server): block files that are not ready from being published - #377
fix(server): block files that are not ready from being published#377yuvrajjsingh0 wants to merge 1 commit into
Conversation
Changed Files
|
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughFile download tasks now log failures explicitly, while shared readiness checks prevent incomplete files from being used during package creation, release construction, or release serving. ChangesFile readiness enforcement
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant PackageOrReleaseHandler
participant FileDatabase
participant FileReadinessUtils
Client->>PackageOrReleaseHandler: create or serve release
PackageOrReleaseHandler->>FileDatabase: fetch referenced files
FileDatabase-->>PackageOrReleaseHandler: file metadata
PackageOrReleaseHandler->>FileReadinessUtils: validate readiness
FileReadinessUtils-->>PackageOrReleaseHandler: success or pending keys
PackageOrReleaseHandler-->>Client: continue or return error
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
904863c to
18b8f18
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@airborne_server/src/release.rs`:
- Around line 1385-1393: Update the refusal log in the release-serving readiness
check to describe every failed readiness condition, including missing or invalid
size as well as missing checksum. Keep the existing not_ready reporting and
error return behavior unchanged, but revise the message so zero-sized files are
diagnosed accurately.
- Around line 1383-1394: Update the release file-lookup flow around
not_ready_file_keys to retain the complete set of requested file keys and verify
every requested key was resolved. Treat lookup errors and partial Ok(files)
results as failures, log the missing or lookup error, and return
ABError::InternalServerError instead of falling through to the placeholder
response or serving the release.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: d5d42fe4-6e5e-44ef-a3fb-880d6abd5a17
📒 Files selected for processing (5)
airborne_server/src/file.rsairborne_server/src/file/utils.rsairborne_server/src/package.rsairborne_server/src/release.rsairborne_server/src/release/utils.rs
|
Pushed 2399209 addressing the file-lookup review. The finding was valid. The readiness gate only inspected rows the lookup returned, so
Change
Matching on the parsed Validation
I verified Those are not in the commit — the amend on this branch removed the test module from NoteThe amend introduced a stray character in a doc comment — |
`bulk_create_files` inserts each row with `size = 0` and an empty checksum, returns 202, and fills the row in from a detached task. If that download fails the task's error was dropped and the placeholder row stayed in the table indefinitely. Nothing downstream distinguished a placeholder from a real file. The package and release paths checked only that the referenced row existed, so a placeholder could be packaged and released, and the served manifest then carried an empty checksum. Both SDKs skip integrity verification when the manifest checksum is empty, so a device receiving that manifest installs bytes that were never verified against anything. Add a readiness predicate (bytes present and checksum present) and enforce it where files are published: - package creation, where existing was previously conflated with usable - release creation and update, via the shared `build_overrides`, before anything is persisted to Superposition Release serving and the build artifact path are deliberately left alone. Serving is the hot path, and a release that references a bad file is better served as before than turned into a 500 that stops devices updating at all; with creation gated, a new release cannot reference one. The detached bulk task now logs why a file failed to become ready instead of discarding the error. `create_file` validates size and checksum synchronously and `upload_file` deletes its row when the upload fails, so the bulk endpoint is the only source of persistent placeholder rows. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
d8df34a to
30466f4
Compare
Problem
bulk_create_filesinserts each row as a placeholder and fills it in later:Nothing awaits that task, so a failed download left the placeholder row in place with no record of why.
Nothing downstream distinguished a placeholder from a real file:
create_packagechecked onlyfiles.len() != request.files.len()— that the rows exist, not that they are usable.build_overrides(shared by release create and update) checked only that none were missing.serve_release_handlercopiedfile.checksumstraight into the manifest.So a placeholder could be packaged, released, and served, and the manifest reaching devices carried
checksum: "". Both SDKs skip integrity verification when the checksum is empty (UpdateTask.kt:865,AJPRemoteFileUtil.swift:139), so the device installs bytes that were never verified against anything. That is what turns an incomplete upload into a supply-chain problem rather than just a broken build.Audit reference: S3 (and it closes the server half of S2).
Change
A readiness predicate — bytes present and checksum present — enforced at three points:
create_packagebuild_overrides(release create and update)serve_release_handlerServing refuses the request instead of emitting a manifest with an empty checksum. That leaves devices on the bundle they already booted, which is the safe outcome; the alternative ships unverified bytes. This also covers releases created before this gate existed, which the create-time gates cannot retroactively fix.
The detached bulk task now logs why a file failed to become ready, distinguishing download failure from a DB failure after a successful download.
Scope notes
create_filevalidates size and checksum synchronously (64 hex chars, size > 0) andupload_filedeletes its row when the S3 upload fails — sobulk_create_filesis the only source of persistent placeholder rows.get_release,list_releases) are deliberately not gated. They are authenticated dashboard reads, and an operator needs to be able to see a broken release in order to diagnose it.statuscolumn. That needs no migration and no backfill, and it correctly classifies rows that already exist. An explicit state machine would be the better long-term model but is a bigger change than this fix warrants.Operational impact
A deployment that already has placeholder rows referenced by a live release will now get a 500 on that release's config, with the offending file keys in the log:
That is intentional and worth calling out in review: those releases were already shipping unverifiable bundles. Devices stay on their current bundle until the file is re-created. Worth a check for
size = 0rows against live releases before rolling this out.Testing
7 unit tests on the predicate and gate, all passing:
a_bulk_created_placeholder_is_not_readyasserts against the exact row shapebulk_create_filesinserts. The half-populated and whitespace cases cover a checksum with no bytes, bytes with no checksum, and a whitespace-only checksum that would pass a naiveis_empty().Verified by inspection that each gate sits before its write:
build_overridesis awaited atrelease.rs:421well beforecreate_experiment().send(), and both public routes (serve_release,serve_release_v2) funnel through the guardedserve_release_handler.Full suite: 17 passed.
cargo fmt --checkandcargo clippy --all-targets -- -Dwarningspass.Docs
No documentation change applies.
bulk_create_filesis not in the Smithy service (onlyCreateFileis) and is not described anywhere inairborne_docs/; the new 400/500 responses fall under theBadRequestError/InternalServerErroralready declared service-wide insmithy/models/main.smithy, so the API reference does not need regenerating. The CLI flows documented inreact-native-cli/remote-files-and-packages.mduseCreateFile/UploadFile, both of which already produce a real checksum or fail, so they are unaffected.🤖 Generated with Claude Code
Summary by CodeRabbit