Consume dunite-geoip and dunite-image-upload (DEV-531) #458
Loading…
Reference in a new issue
No description provided.
Delete branch "refactor/DEV-531-consume-dunite-geoip-image"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes DEV-531. DEV-525 extracted this code out of bunyip so a8n-tools could use it; this is the other half, where bunyip stops carrying the original.
Net -329 lines across the two commits. No behaviour change anywhere.
What moved
crates/bunyip-domain/src/services/geoip.rs(the whole file)dunite_geoip::{GeoIpService, GeoIpError}is_non_public_ip,login_location_decision,LoginLocationDecisioninservices/auth.rsdunite_geoip::*sniff_image_mime,enforce_dimensions,MAX_AVATAR_SIZE,ALLOWED_MIME_TYPES,MAX_IMAGE_DIMENSIONinhandlers/avatar.rsdunite_image_upload::{validate_image, ImagePolicy}services/geoip.rssurvives as a re-export so everycrate::services::GeoIpServicepath in bunyip is untouched. Storage and serving stay inhandlers/avatar.rs; only the validation left.The shared implementations are byte-identical to what they replace - which is exactly why now was the moment to converge them, before either copy drifted.
One visible difference
GeoIpService::newnow returnsdunite_geoip::GeoIpErrorrather thanAppError. The only caller logs it viaDisplay, so nothing needed converting. The shared crates own their errors deliberately: returningdunite_core::AppErrorwould force every consumer onto onedunite-corerevision, the version cascade DEV-515 backed out of.Test count: 604 -> 596, deliberately
Eight tests removed here, all of which re-tested logic that a dependency now owns:
geoip.rsnon_public_ip_detectionandlogin_location_decision_branchesfromauth.rsavatar.rs, replaced by 2 that cover what is still bunyip's to get right (the error conversion, and that the shared policy's cap still matches theuser_avatars.size_bytesCHECK - if those diverged, a valid upload would pass validation and then fail on insert with a database error instead of a useful message)Upstream,
dunite-geoipanddunite-image-uploadcarry 21 tests covering all of the above and more: a declared dimension bomb, unrecognised content failing closed, the absence of SVG from the allowlist, and that the error messages describe the rule rather than the bytes. None of those four were tested in bunyip.Two things deliberately left alone
inferandimagesizestay direct dependencies ofbunyip-api, for the feedback-attachment path (BUNYIP-90). Its allowlist admits non-images (text/plain), so it does not fitImagePolicy. Folding that surface in is a separate decision, not a side effect of this one..BINfails to load; a8n exits. Both are defensible - bunyip treats alerts as best-effort, a8n treats a set-but-broken path as a misconfiguration an operator must see - and they were already divergent before this PR. Worth a decision at some point, but changing it here would be a behaviour change smuggled into a de-duplication.Also
Bumps every dunite pin in the workspace from
cc10e83to the merged302af65, so bunyip stays on one git checkout rather than two. Verified additive:git diff cc10e83..302af65in dunite touches only the two new crates and the manifests.just check-build,just check-clippyandjust check-fmtare clean.The other half of the DEV-525 extraction. `handlers/avatar.rs` keeps storage and serving and drops its copies of the checks: `sniff_image_mime`, `enforce_dimensions`, `MAX_AVATAR_SIZE`, `ALLOWED_MIME_TYPES` and `MAX_IMAGE_DIMENSION` all come from the shared crate now, via `ImagePolicy::avatar()` which carries bunyip's exact numbers. No behaviour change: every check still runs against file content, never the declared MIME or the filename, and the limits are the same 2 MiB / 4096px / PNG-JPEG-WebP-GIF. The error wording is now the crate's, which describes the rule and never the bytes, converted to `AppError::validation("avatar", ...)` at one call site so the client still attaches it to the right input. `infer` and `imagesize` stay direct dependencies for the feedback-attachment path (BUNYIP-90), whose allowlist admits non-images and so does not fit `ImagePolicy`. Folding that surface in is a separate decision, not a side effect of this one. Four unit tests move upstream, replaced by two that cover what is still bunyip's to get right: the error conversion, and that the shared policy's cap still matches the `user_avatars.size_bytes` CHECK - if the two ever diverged, a valid upload would pass validation and then fail on insert with a database error instead of a useful message. `dunite-image-upload` has eleven tests covering the rest, including a declared dimension bomb and the absence of SVG from the allowlist, neither of which was tested here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FcwfAHYwMmiAYbMrCc7cJG