From e48d9d09630fc87b2f97876a33b473c401161cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20V=C3=A1squez?= Date: Tue, 24 Mar 2026 16:43:41 -0600 Subject: [PATCH] Fix null byte ArgumentError in API::ResultsController#create Checker results sometimes contain null bytes (\x00) in string fields like output. PostgreSQL rejects these when saving to text columns, causing an ArgumentError: "string contains null byte". Add a before_action filter that strips null bytes from result params before processing. Sentry: https://ombu-ai.sentry.io/issues/7361326341/ --- app/controllers/api/results_controller.rb | 10 ++++++++++ .../api/results_controller_spec.rb | 20 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/app/controllers/api/results_controller.rb b/app/controllers/api/results_controller.rb index bc4f4cc..4f1b15f 100644 --- a/app/controllers/api/results_controller.rb +++ b/app/controllers/api/results_controller.rb @@ -1,6 +1,7 @@ module API class ResultsController < BaseController before_action :authenticate_api_key! + before_action :sanitize_result_params!, only: :create def create @rails_release = RailsRelease.find_by(version: params[:rails_version]) @@ -22,6 +23,15 @@ def create private + def sanitize_result_params! + if params[:result].is_a?(ActionController::Parameters) + params[:result].each_key do |key| + value = params[:result][key] + params[:result][key] = value.delete("\x00") if value.is_a?(String) + end + end + end + def authenticate_api_key! api_key = request.headers['RAILS-BUMP-API-KEY'] diff --git a/spec/controllers/api/results_controller_spec.rb b/spec/controllers/api/results_controller_spec.rb index b14a766..145479f 100644 --- a/spec/controllers/api/results_controller_spec.rb +++ b/spec/controllers/api/results_controller_spec.rb @@ -73,6 +73,26 @@ end end + context "when result params contain null bytes" do + it "strips null bytes and processes successfully" do + request.headers.merge!(headers) + + post :create, params: { + rails_version: rails_release.version, + compat_id: compat.id, + dependencies: compat.dependencies, + result: { + success: true, + strategy: "some_strategy", + output: "some output\x00with null bytes" + } + } + + expect(response).to have_http_status(:ok) + expect(compat.reload.status).to eq("compatible") + end + end + context "if result processing fails" do it "returns unprocessable entity" do allow_any_instance_of(Compat).to receive(:process_result).and_return(false)