daisy / ace

Ace by DAISY, an Accessibility Checker for EPUB
MIT License
74 stars 22 forks source link

Running ace in headless mode stopped working in v1.2.8 and 1.3.0 #392

Open josteinaj opened 11 months ago

josteinaj commented 11 months ago

the version of Ace impacted by the issue (as returned by the ace -v command).

1.2.8, 1.3.0, 1.3.1

the version of Node used to run Ace (as returned by the node -v command).

v16.19.1

your operating system and version.

Linux / Docker

if the issue is a bug when running Ace: the error message as produced in the log file (you can enable debug logging with the --verbose option).

Version 1.2.8:

(…)
Error: Cannot find module 'electron'
(…)

Version 1.3.0 and 1.3.1:

/usr/local/lib/node_modules/@daisy/ace/node_modules/electron/dist/electron: error while loading shared libraries: libnss3.so: cannot open shared object file: No such file or directory

if possible, let us know if you can share a sample input file to help us reproduce the issue.

docker run --rm -it node:16 bash
npm install @daisy/ace@1.3.1 --location=global
ace
danielweck commented 3 months ago

Hello, Ace with Puppeteer (which is now deprecated but still available when installing Ace) runs without any special configuration in a headless Docker Linux container, but Electron requires xvfb virtual framebuffer (display server) and some configuration.

See the following Dockerfile demonstration:

https://github.com/daisy/ace/blob/master/Dockerfile

To test this, simply place a file named book.epub in the directory and call docker.sh:

https://github.com/daisy/ace/blob/master/docker.sh

Obviously, this is not ideal and I would like to better understand if the Electron BrowserWindow code which I suspect causes the virtual buffer requirement can be configured to run headless Chromium (assuming this is how Puppeteer gets around this). There is also the "no sandbox" command line argument which can be integrated directly in Javascript when launching the Electron instance (I suspect Puppeteer includes this by default).

Further information: https://www.electronjs.org/docs/latest/tutorial/testing-on-headless-ci

jenstroeger commented 1 month ago

Thank you for this thread, something I meant to ask for quite some time! In my Dockerfile I use

# syntax=docker/dockerfile:1
FROM ubuntu:22.04

...

# https://deb.nodesource.com/
# https://nodejs.org/en/download/
# https://github.com/daisy/ace
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor --output /etc/apt/keyrings/nodesource.gpg && \
  echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \
  apt-get update && apt-get install --yes --no-install-recommends nodejs && \
  npm install --global @daisy/ace@1.3.2

# https://www.ubuntuupdates.org/package/google_chrome/stable/main/base/google-chrome-stable
# https://googlechromelabs.github.io/chrome-for-testing/
RUN apt-key list && \
  curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
  sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' && \
  apt-get update && \
  apt-get install --yes --no-install-recommends google-chrome-stable=123.0.6312.* && \
  rm /etc/apt/sources.list.d/google.list /etc/apt/sources.list.d/google-chrome.list && \
  apt-get update && \
  curl --output /tmp/chromedriver-linux64.zip https://storage.googleapis.com/chrome-for-testing-public/123.0.6312.105/linux64/chromedriver-linux64.zip && \
  unzip -d /tmp/ /tmp/chromedriver-linux64.zip && \
  cp /tmp/chromedriver-linux64/chromedriver /usr/bin/

which, when running, produces this error:

Spawning subprocess: /usr/bin/ace /tmp/tmpi147nqu8/some.epub 1>&2
[228:0622/120936.700186:FATAL:setuid_sandbox_host.cc(158)] The SUID sandbox helper binary was found, but is not configured correctly. Rather than run without sandboxing I'm aborting now. You need to make sure that /usr/lib/node_modules/@daisy/ace/node_modules/electron/dist/chrome-sandbox is owned by root and has mode 4755.
/usr/lib/node_modules/@daisy/ace/node_modules/electron/dist/electron exited with signal SIGTRAP
[230:0100/000000.722930:ERROR:zygote_linux.cc(661)] write: Broken pipe (32)

Following the error’s suggestion You need to make sure that… didn’t actually solve the problem 🤔

@danielweck I’ll review your linked Dockerfile and also PR https://github.com/daisy/ace/pull/373, and hopefully that addresses the issue I’ve encountered here.

danielweck commented 1 month ago

yes, the chrome sandbox ownership / mode error is solved in my docker script

jenstroeger commented 1 month ago

Thanks @danielweck — turns out that installing the virtual fb https://github.com/daisy/ace/blob/ba239723a3efd301c2bbf875fd9b337476353a69/Dockerfile#L91 and passing the right options worked.

Just out of curiosity regarding how ACE is being run here https://github.com/daisy/ace/blob/ba239723a3efd301c2bbf875fd9b337476353a69/Dockerfile#L103

danielweck commented 1 month ago

Hello, 'ace' is synonym with 'ace-electron', and 'ace-puppeteer' is the legacy "runner" for the Deque Axe evaluation engine. Both the Electron and Puppeteer "runners" launch Chromium web browser instances (webviews) to execute the Axe JavaScript, but they do it in slightly different ways. Unfortunately the Electron "runner" is not truly headless, thus the virtual framebuffer hacks. Older versions of Daisy Ace (CLI) used to run Puppeteer by default but this potentially caused discrepancies with the Daisy Ace App (GUI) accessibility reports, due to the application relying on Electron instead of Puppeteer. Daisy Ace (CLI) has since switched to Electron by default, which not only introduced much needed consistency, but also improved evaluation performance (also note that the Chromium version shipped in Ace's current Puppeteer integration is older than the version shipped with Electron). The Puppeteer Ace command line launcher remains available (and requires no virtual framebuffer hack in headless Docker-like containers) but this is not the recommended method, for the reasons previously given. I hope this helps.