Files
sure/Dockerfile
T
125666f59d fix(pdf-vision): render PDFs with poppler-utils + surface a concrete admin failure reason (#3275)
* Fix PDF vision path failing when poppler-utils is missing

The Docker image omitted poppler-utils, so the OpenAI PDF vision path
(which renders pages with pdftoppm before sending them upstream) always
failed and the admin AI status page surfaced a generic "request failed"
code rather than a useful reason.

- install poppler-utils in the Docker base image (pdftoppm for the
  vision render path)
- add an optional failure_code to Provider::Error, so probe errors can
  carry a machine-readable reason
- in Provider::Openai::PdfProcessor#convert_pdf_to_images, check
  pdftoppm's return value and -- when the binary is genuinely missing,
  raise a Provider::Openai::Error with failure_code :render_missing_binary
  while preserving the existing [] fallback for other render failures
- register the :render_missing_binary code in the admin locale so the AI
  status page shows a concrete, actionable message instead of "request
  failed"
- AiHealth::Probe#failure_code now falls through to the default codes
  when an error's failure_code is nil, instead of returning nil
- regression tests covering both the missing-binary and the
  present-but-fails cases

Fixes the "PDF vision/native path" system check on instances where the
image is built from the checked-in Dockerfile.

* Fix missing-binary detection and preserve failure_code across the error boundary

- convert_pdf_to_images: Kernel#system returns nil (not false) when the executable is absent; raise the coded error on rendered.nil? so a missing pdftoppm yields :render_missing_binary instead of a blank conversion. - Provider::Error#as_json + default_error_transformer: carry failure_code through serialization and error re-wrapping. - Drop the binary_missing? helper (nil result is the authoritative signal) and update regression tests to stub the real nil return value. - Add coverage for failure_code serialization/transformation.

* Fix Provider::Error transformer syntax error and cover Faraday branch

Addresses jjmata's blocking change-request: app/models/provider.rb:54
used a postfix `if` modifier inside a hash-argument/method-call argument
list, which is not valid Ruby. `ruby -c` failed to parse the file, so the
base class every provider inherits from could not autoload and the whole
app (boot, requests, jobs, tests) was down.

Rewrite default_error_transformer to build the optional failure_code
keyword once (only when the error exposes a truthy code) and splat it, so
both the Faraday::Error branch and the generic branch carry the code with
no syntax error and no nil kwarg.

Also add the two Faraday-branch regression tests that were missing
(failure_code preservation + response-body-to-details extraction),
guarding this exact class of broken-argument bug with real assertions.

Verification: ruby -c passes on provider.rb, pdf_processor.rb, probe.rb,
and both test files; plus a behavioral harness against the real
provider.rb source covering the coded/plain/nil-code, Faraday-coded,
Faraday-no-code, nil-response, and generic-error paths (19/19 pass).

Ref: we-promise/sure#3275

* Document the methods added or changed by this PR

* Add poppler-utils to devcontainer image

---------

Co-authored-by: hermes-on-behalf-of-jon <hermes@nousresearch.com>
Co-authored-by: jaysbeekay <jaysbeekay@users.noreply.github.com>
Co-authored-by: sure-admin <sure-admin@splashblot.com>
2026-08-31 23:27:04 +02:00

65 lines
2.1 KiB
Docker

# syntax = docker/dockerfile:1
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.4.9
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim AS base
# Rails app lives here
WORKDIR /rails
# Install base packages
# poppler-utils provides pdftoppm, required for the PDF vision processing path
RUN apt-get update -qq \
&& apt-get install --no-install-recommends -y curl libvips postgresql-client libyaml-0-2 procps libjemalloc2 poppler-utils \
&& rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Set production environment
ARG BUILD_COMMIT_SHA
ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development" \
BUILD_COMMIT_SHA=${BUILD_COMMIT_SHA}
# Throw-away build stage to reduce size of final image
FROM base AS build
# Install packages needed to build gems
RUN apt-get update -qq \
&& apt-get install --no-install-recommends -y build-essential libpq-dev git pkg-config libyaml-dev \
&& rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Install application gems
COPY .ruby-version Gemfile Gemfile.lock ./
RUN bundle install \
&& rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git \
&& bundle exec bootsnap precompile --gemfile -j 0
# Copy application code
COPY . .
# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile -j 0 app/ lib/
# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
# Final stage for app image
FROM base
# Run and own only the runtime files as a non-root user for security
RUN groupadd --system --gid 1000 rails && \
useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash
USER 1000:1000
# Copy built artifacts: gems, application
COPY --chown=rails:rails --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --chown=rails:rails --from=build /rails /rails
# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]