feat: Validate version when building file URL CU-30er0v6 - #24
Draft
Skoda091 wants to merge 2 commits into
Draft
Conversation
After bumping erlexec to 2.2.2 (OTP 27+), the remaining locked deps (ecto 3.7, ssl_verify_fun 1.1.6, mix_test_watch 1.1.0) no longer compiled on any single OTP release, making mix test unrunnable. Updates ecto/ecto_sql, ssl_verify_fun and mix_test_watch with their transitive deps. Affects only bow's standalone dev/test environment - consumers resolve these against their own lockfiles. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bow.url/2,3 (and Bow.Ecto.url/3,4) happily built a URL for any version atom, even one the uploader never defined, silently producing links to files that do not exist. The requested version is now validated against the uploader's URL-addressable versions. Since versions/1 describes what is generated on store, and transform/3 can produce derived versions (next_versions) while filename/2 can alias two versions to the same stored file, the addressable set is a new overridable callback url_versions/1, defaulting to versions(file). An undefined version logs a warning by default; set config :bow, on_undefined_url_version: :raise to raise Bow.Error instead (recommended for test/dev, and for prod once clean). CU-30er0v6 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the loophole described in CU-30er0v6:
Bow.url/2,3andBow.Ecto.url/3,4build a URL for any version atom, even one the uploader never defined, silently producing links to files that don't exist. The requested version is now validated, so version definitions in uploaders can be trusted (e.g. by a cleaner script) and a "finger slip" version surfaces immediately instead of as a dead link.Straight
version in versions(file)validation is not possible:versions/1describes what is generated on store, whiletransform/3can return derived versions ({:ok, file, next_versions}) andfilename/2can alias two versions to the same stored file — both patterns are exercised by bow's own test suite (PipelineUploader,UrlUploader) and by the API. The URL-addressable set is therefore a new overridable callbackurl_versions/1, defaulting toversions(file), which is correct for most uploaders.Changes
Bow.Uploadergets an overridableurl_versions/1callback (default:versions(file)) declaring which versions URLs may be built forBow.url/3(the funnel forBow.Ecto.urltoo) validates the requested version againsturl_versions/1Logger.warningby default;config :bow, on_undefined_url_version: :raiseraisesBow.Errorinsteadurl_versions/1extendingversions/1(derived + aliased versions)url_versions/1ecto/ecto_sql,ssl_verify_fun,mix_test_watch) — after the erlexec 2.2.2 bump (Bump erlexec #23, requires OTP 27) the old lock no longer compiled on any OTP, somix testwas unrunnable; this only affects bow's standalone dev env, consumers resolve deps via their own lockfilesWhy warn-by-default instead of raise (as the ticket suggests)
URL building runs inside hot view-rendering paths of the API (candidate CV links among them). An audit of the API found live call sites relying on the loophole today, so raising unconditionally would turn currently-working URLs into 500s:
Cv/CoverLetter/ImportCv/ApplicationCvuploaders — for.pdffilesversions/1returns[:original, :copy], yet views request:pdf(works only becausefilename(:copy) == filename(:pdf))Attachmentuploader —.pdffiles map to DB kind"document", whose view branches request:pdf, whileversions/1returns[:original, :copy, :pdf_thumbnail]ReferrerAvatar(portal + admin) — read-only uploaders with default[:original], but call sites request:normaland:thumbRollout plan:
on_undefined_url_version: :raisein test/dev so the suite catches stragglers:raisein production; potentially flip the library default in a next majorType of change
Pre-merge checklist
mix test: 51 tests, 0 failures, 42 excluded — the default-excluded:s3/:ectotags, same as before)mix.exssays0.4.3while the latest tag is0.5.0(API pins the tag), worth reconciling when releasingNotes
recruitee/api🤖 Generated with Claude Code