🤖 From Claude:
What
FormSubmission#persist_answer (extracted from EventRegistrationServices::PublicRegistration on maebeale/public-form-endpoint) raises FormSubmission::UnreadableUpload when a file_upload field's value is a forged or stale direct-upload signed id.
EventRegistrationServices::BulkPayment#call rescues only ActiveRecord::RecordInvalid, so the exception escapes.
Impact
Events::BulkPaymentFormSubmissionsController#create is a public, account-free endpoint. A bulk-payment form carrying a file_upload field would 500 instead of re-rendering with a form error. Before the extraction this path stored the raw value as text and could not raise.
Reachability is currently narrow — the bulk-payment new view renders no file input, so a legitimate submission won't produce the value; it takes a crafted POST or a stale signed id. That's why it's filed rather than fixed inline.
Fix
Add the rescue alongside the existing one in app/services/event_registration_services/bulk_payment.rb:
rescue FormSubmission::UnreadableUpload => e
Result.new(success?: false, form_submission: nil, errors: [ e.message ])
PublicRegistration and PublicFormSubmission both already rescue it — this is the one caller that doesn't.
Test
Request spec on POST /events/:event_id/bulk_payment_form_submissions with a file_upload field and a garbage signed id: expect :unprocessable_content with the error surfaced, not a raised exception.
🤖 From Claude:
What
FormSubmission#persist_answer(extracted fromEventRegistrationServices::PublicRegistrationonmaebeale/public-form-endpoint) raisesFormSubmission::UnreadableUploadwhen afile_uploadfield's value is a forged or stale direct-upload signed id.EventRegistrationServices::BulkPayment#callrescues onlyActiveRecord::RecordInvalid, so the exception escapes.Impact
Events::BulkPaymentFormSubmissionsController#createis a public, account-free endpoint. A bulk-payment form carrying afile_uploadfield would 500 instead of re-rendering with a form error. Before the extraction this path stored the raw value as text and could not raise.Reachability is currently narrow — the bulk-payment
newview renders no file input, so a legitimate submission won't produce the value; it takes a crafted POST or a stale signed id. That's why it's filed rather than fixed inline.Fix
Add the rescue alongside the existing one in
app/services/event_registration_services/bulk_payment.rb:PublicRegistrationandPublicFormSubmissionboth already rescue it — this is the one caller that doesn't.Test
Request spec on
POST /events/:event_id/bulk_payment_form_submissionswith afile_uploadfield and a garbage signed id: expect:unprocessable_contentwith the error surfaced, not a raised exception.