diff --git a/.github/workflows/on-pull-request-images.yml b/.github/workflows/on-pull-request-images.yml new file mode 100644 index 00000000..51d56a3a --- /dev/null +++ b/.github/workflows/on-pull-request-images.yml @@ -0,0 +1,49 @@ +name: PR Images + +# The sandbox and browser images publish only on push to main, so a change to +# their build contexts reached main with no pre-merge check. This builds them on +# the pull request — amd64 only and without pushing, so a broken Dockerfile +# fails the PR instead of the deploy. arm64 stays covered by the publish build. +on: + pull_request: + branches: [main] + paths: + - "deploy/sandbox/**" + - "deploy/browser/**" + - ".github/workflows/on-pull-request-images.yml" + +concurrency: + group: on-pull-request-images-${{ github.event.pull_request.number }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + sandbox: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 + - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 + with: + context: deploy/sandbox + platforms: linux/amd64 + push: false + cache-from: type=gha,scope=sandbox + + browser: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 + - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 + with: + context: deploy/browser + platforms: linux/amd64 + push: false + cache-from: type=gha,scope=browser diff --git a/deploy/browser/Dockerfile b/deploy/browser/Dockerfile index a693691b..e9120687 100644 --- a/deploy/browser/Dockerfile +++ b/deploy/browser/Dockerfile @@ -31,7 +31,8 @@ RUN apt-get update \ > /etc/apt/sources.list.d/nodesource.list \ && apt-get update \ && apt-get install -y --no-install-recommends \ - fonts-liberation fonts-noto-cjk fonts-noto-color-emoji nodejs x11vnc xvfb \ + fonts-liberation fonts-noto-cjk fonts-noto-color-emoji \ + nodejs tzdata x11vnc xvfb \ && rm -rf /var/lib/apt/lists/* \ && install -d -m 0755 /opt/druks-browser \ && cd /opt/druks-browser \ @@ -52,6 +53,21 @@ RUN apt-get update \ && install -m 0755 /tmp/pinchtab /usr/local/bin/pinchtab \ && rm -f /tmp/pinchtab /tmp/pinchtab-checksums.txt +# Real Google Chrome, so the login browser presents Chrome's fingerprint rather +# than the bundled chromium's — a login gate reads the difference. Google ships +# no arm64 Linux build, so this is amd64-only; session-launch falls back to the +# bundled chromium where Chrome is absent. +# hadolint ignore=DL3008 +RUN if [ "${TARGETARCH}" = "amd64" ]; then \ + curl -fsSL https://dl.google.com/linux/linux_signing_key.pub \ + | gpg --dearmor -o /etc/apt/keyrings/google-chrome.gpg \ + && echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/google-chrome.gpg] https://dl.google.com/linux/chrome/deb/ stable main" \ + > /etc/apt/sources.list.d/google-chrome.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends google-chrome-stable \ + && rm -rf /var/lib/apt/lists/*; \ + fi + RUN useradd --create-home --shell /bin/bash druks COPY session-launch session-export /usr/local/bin/ diff --git a/deploy/browser/session-launch b/deploy/browser/session-launch index ef4155dc..56e20d18 100755 --- a/deploy/browser/session-launch +++ b/deploy/browser/session-launch @@ -13,6 +13,11 @@ const META_PATH = path.join(SESSION_ROOT, "state.meta.json"); const PROFILE_ARCHIVE_PATH = path.join(SESSION_ROOT, "state.tar.gz"); const STORAGE_STATE_PATH = path.join(SESSION_ROOT, "state.json"); const PROFILE_PATH = path.join(SESSION_ROOT, "profile"); +// Real Google Chrome when the image carries it (amd64), else the bundled +// chromium (arm64). A login gate reads the Chromium-vs-Chrome brand split, so +// the login browser must be real Chrome wherever it can be. +const CHROME_PATH = "/opt/google/chrome/chrome"; +const channel = fs.existsSync(CHROME_PATH) ? "chrome" : undefined; const RUNTIME_PATH = path.join(SESSION_ROOT, ".runtime"); const PID_PATH = path.join(RUNTIME_PATH, "launcher.pid"); const READY_PATH = path.join(RUNTIME_PATH, "ready.json"); @@ -87,6 +92,7 @@ async function main() { let isReady = false; try { context = await chromium.launchPersistentContext(PROFILE_PATH, { + channel, args: [ "--remote-debugging-address=127.0.0.1", "--remote-debugging-port=9222",