From 5ad6fa81e3b5b8766363543e3e763e7e93ea875b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 24 Feb 2026 20:15:39 -0600 Subject: [PATCH] Fix v3.22.0 build, improve stability, and set up for community maintenance - Add libfido2-dev, libcbor-dev to build deps; libfido2-1, libcbor0 to runtime (fixes #135) - Make bridge binaries read-only to block built-in auto-updater at runtime - Add HEALTHCHECK to Dockerfile - Fix long-uptime stdin stability: replace cat pipe with sleep infinity - Clean up stale GPG agent sockets on container startup - Update maintainer label - Repoint build.yaml to dancwilliams Docker Hub and GHCR repos - Use clean version/latest tags (drop -build suffix) - Fix missing checkout in merge job - Add workflow_dispatch and pip install to update-check.yaml - Remove Gitee mirror workflow - Remove legacy deb build (Dockerfile, workflow, and deb/ directory) --- .github/workflows/build.yaml | 60 ++++++++-------------- .github/workflows/deb.yaml | 79 ----------------------------- .github/workflows/mirror.yaml | 27 ---------- .github/workflows/update-check.yaml | 7 ++- build/Dockerfile | 14 +++-- build/entrypoint.sh | 17 ++++++- deb/Dockerfile | 28 ---------- deb/PACKAGE | 1 - deb/entrypoint.sh | 49 ------------------ deb/gpgparams | 8 --- deb/install.sh | 16 ------ 11 files changed, 51 insertions(+), 255 deletions(-) delete mode 100644 .github/workflows/deb.yaml delete mode 100644 .github/workflows/mirror.yaml delete mode 100644 deb/Dockerfile delete mode 100644 deb/PACKAGE delete mode 100644 deb/entrypoint.sh delete mode 100644 deb/gpgparams delete mode 100644 deb/install.sh diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index defc7de..87bf37a 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -13,9 +13,9 @@ on: workflow_dispatch: env: - GHCR_REPO: shenxn/protonmail-bridge-docker - DOCKERHUB_REPO: shenxn/protonmail-bridge - DOCKER_REPO_DEV: ghcr.io/shenxn/protonmail-bridge + DOCKERHUB_REPO: dancwilliams/protonmail-bridge + GHCR_REPO: ghcr.io/dancwilliams/protonmail-bridge-docker + DOCKER_REPO_DEV: ghcr.io/dancwilliams/protonmail-bridge PLATFORMS: linux/amd64,linux/arm64/v8,linux/arm/v7,linux/riscv64 jobs: @@ -24,11 +24,10 @@ jobs: if: github.ref != 'refs/heads/master' steps: - name: Checkout - uses: actions/checkout@master + uses: actions/checkout@v4 - name: Set version - id: version - run: echo "version=`cat VERSION`" >> $GITHUB_ENV + run: echo "version=$(cat VERSION)" >> $GITHUB_ENV - name: Docker meta id: meta @@ -46,18 +45,16 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - with: - driver-opts: network=host - - name: Build and push by digest + - name: Build and push id: build uses: docker/build-push-action@v6 with: labels: ${{ steps.meta.outputs.labels }} - outputs: type=image,"name=${{ env.DOCKER_REPO_DEV }}",push-by-digest=false,name-canonical=true,push=true context: ./build file: ./build/Dockerfile tags: "${{ env.DOCKER_REPO_DEV }}:dev-${{ github.ref_name }}" + push: true build-args: | version=${{ env.version }} @@ -88,7 +85,7 @@ jobs: - linux/riscv64 steps: - name: Checkout - uses: actions/checkout@master + uses: actions/checkout@v4 - name: Prepare run: | @@ -96,16 +93,7 @@ jobs: echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV - name: Set version - id: version - run: echo "version=`cat VERSION`" >> $GITHUB_ENV - - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - images: | - ${{ env.DOCKERHUB_REPO }} - ${{ env.GHCR_REPO }} + run: echo "version=$(cat VERSION)" >> $GITHUB_ENV - name: Login to Docker Hub uses: docker/login-action@v3 @@ -131,15 +119,9 @@ jobs: uses: docker/build-push-action@v6 with: platforms: ${{ matrix.platform }} - labels: ${{ steps.meta.outputs.labels }} - outputs: type=image,"name=name=${{ env.DOCKERHUB_REPO }},${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=false + outputs: type=image,name=${{ env.DOCKERHUB_REPO }},push-by-digest=true,name-canonical=true,push=true context: ./build file: ./build/Dockerfile - tags: | - "${{ env.DOCKERHUB_REPO }}:build" - "${{ env.DOCKERHUB_REPO }}:${{ env.version }}-build" - "${{ env.GHCR_REPO }}:build" - "${{ env.GHCR_REPO }}:${{ env.version }}-build" provenance: false sbom: false build-args: | @@ -159,12 +141,14 @@ jobs: if-no-files-found: error retention-days: 1 - merge: runs-on: ubuntu-latest needs: - build steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Download digests uses: actions/download-artifact@v4 with: @@ -173,8 +157,7 @@ jobs: merge-multiple: true - name: Set version - id: version - run: echo "version=`cat VERSION`" >> $GITHUB_ENV + run: echo "version=$(cat VERSION)" >> $GITHUB_ENV - name: Login to Docker Hub uses: docker/login-action@v3 @@ -191,8 +174,6 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - with: - driver-opts: network=host - name: Docker meta id: meta @@ -202,25 +183,24 @@ jobs: ${{ env.DOCKERHUB_REPO }} ${{ env.GHCR_REPO }} tags: | - type=raw,enable=true,value=${{ env.version }}-build - type=raw,enable=true,suffix=,value=build + type=raw,value=${{ env.version }} + type=raw,value=latest - name: Create manifest list and push working-directory: ${{ runner.temp }}/digests run: | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ $(printf '${{ env.DOCKERHUB_REPO }}@sha256:%s ' *) - docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ - $(printf '${{ env.GHCR_REPO }}@sha256:%s ' *) - name: Run Trivy vulnerability scan uses: aquasecurity/trivy-action@0.30.0 with: - image-ref: "${{ env.DOCKERHUB_REPO }}:${{ env.version }}-build" + image-ref: "${{ env.DOCKERHUB_REPO }}:${{ env.version }}" format: 'sarif' exit-code: 0 severity: 'CRITICAL,HIGH' output: 'trivy-results.sarif' + - name: Upload Trivy scan SARIF report uses: github/codeql-action/upload-sarif@v3 with: @@ -228,5 +208,5 @@ jobs: - name: Inspect image run: | - docker buildx imagetools inspect ${{ env.DOCKERHUB_REPO }}:${{ steps.meta.outputs.version }} - docker buildx imagetools inspect ${{ env.GHCR_REPO }}:${{ steps.meta.outputs.version }} + docker buildx imagetools inspect ${{ env.DOCKERHUB_REPO }}:${{ env.version }} + docker buildx imagetools inspect ${{ env.GHCR_REPO }}:${{ env.version }} diff --git a/.github/workflows/deb.yaml b/.github/workflows/deb.yaml deleted file mode 100644 index ddf4c99..0000000 --- a/.github/workflows/deb.yaml +++ /dev/null @@ -1,79 +0,0 @@ -name: pack from deb - -on: - push: - paths: - - .github/workflows/deb.yaml - - deb/* - - VERSION - pull_request: - paths: - - .github/workflows/deb.yaml - - deb/* - workflow_dispatch: - -env: - DOCKER_REPO: shenxn/protonmail-bridge - DOCKER_REPO_DEV: ghcr.io/shenxn/protonmail-bridge-dev - -jobs: - deb: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@master - - name: Set version - id: version - run: echo "version=`cat VERSION`" >> $GITHUB_ENV - - name: Set repo - id: repo - run: if [[ $GITHUB_REF == "refs/heads/master" ]]; then echo "::set-output name=repo::${DOCKER_REPO}"; else echo "::set-output name=repo::${DOCKER_REPO_DEV}"; fi - - name: Docker meta - id: docker_meta - uses: crazy-max/ghaction-docker-meta@v1 - with: - images: ${{ steps.repo.outputs.repo }} - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - name: Build image without push - uses: docker/build-push-action@v2 - with: - context: ./deb - file: ./deb/Dockerfile - load: true - tags: protonmail-bridge:latest - - name: Scan image - id: scan - uses: anchore/scan-action@v2 - with: - image: protonmail-bridge:latest - fail-build: true - severity-cutoff: critical - acs-report-enable: true - - name: Upload Anchore scan SARIF report - uses: github/codeql-action/upload-sarif@v3 - with: - sarif_file: ${{ steps.scan.outputs.sarif }} - - name: Login to DockerHub - uses: docker/login-action@v1 - if: ${{ github.event_name != 'pull_request' }} - with: - username: ${{ secrets.REGISTRY_USERNAME }} - password: ${{ secrets.REGISTRY_PASSWORD }} - - name: Login to GitHub Container Registry - uses: docker/login-action@v1 - if: ${{ github.event_name != 'pull_request' }} - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.CR_PAT }} - - name: Push image - uses: docker/build-push-action@v2 - with: - context: ./deb - file: ./deb/Dockerfile - tags: | - ${{ steps.repo.outputs.repo }}:latest - ${{ steps.repo.outputs.repo }}:${{ env.version }} - labels: ${{ steps.docker_meta.outputs.labels }} - push: ${{ github.event_name != 'pull_request' }} diff --git a/.github/workflows/mirror.yaml b/.github/workflows/mirror.yaml deleted file mode 100644 index 4e2409b..0000000 --- a/.github/workflows/mirror.yaml +++ /dev/null @@ -1,27 +0,0 @@ -name: Mirroring - -# yamllint disable-line rule:truthy -on: - push: - branches: - - master - - dev - -jobs: - mirror_gitee: - name: Mirror to Gitee - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: Push to Gitee - env: - SSH_KEY: ${{ secrets.GITEE_KEY }} - run: | - mkdir -p ~/.ssh - echo "${SSH_KEY}" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - export GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no -l git" - git remote add gitee git@gitee.com:shenxn/protonmail-bridge-docker.git - git push --tags --force --prune gitee "refs/remotes/origin/*:refs/heads/*" diff --git a/.github/workflows/update-check.yaml b/.github/workflows/update-check.yaml index 0c46ab4..c6ee641 100644 --- a/.github/workflows/update-check.yaml +++ b/.github/workflows/update-check.yaml @@ -10,15 +10,18 @@ on: - .github/workflows/update-check.yaml - update-check.py schedule: - - cron: '0 0 * * *' # runs everyday at midnight + - cron: '0 0 * * *' # runs every day at midnight UTC + workflow_dispatch: jobs: check: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@master + uses: actions/checkout@v4 with: token: ${{ secrets.PERSONAL_TOKEN }} + - name: Install dependencies + run: pip install requests - name: Check Update run: python3 update-check.py ${{ github.event_name == 'pull_request' }} diff --git a/build/Dockerfile b/build/Dockerfile index e90ff25..e38a64d 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -4,7 +4,7 @@ FROM debian:sid-slim AS build ARG version # Install dependencies -RUN apt-get update && apt-get install -y golang build-essential libsecret-1-dev +RUN apt-get update && apt-get install -y golang build-essential libsecret-1-dev libfido2-dev libcbor-dev # Build ADD https://github.com/ProtonMail/proton-bridge.git#${version} /build/ @@ -12,14 +12,18 @@ WORKDIR /build/ RUN make build-nogui vault-editor FROM debian:sid-slim -LABEL maintainer="Simon Felding " +LABEL maintainer="Dan Williams " EXPOSE 25/tcp EXPOSE 143/tcp +# Monitor proton-bridge process health +HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=60s \ + CMD bash -c "pgrep -f proton-bridge || exit 1" + # Install dependencies and protonmail bridge RUN apt-get update \ - && apt-get install -y --no-install-recommends socat pass libsecret-1-0 ca-certificates \ + && apt-get install -y --no-install-recommends socat pass libsecret-1-0 libfido2-1 libcbor0 ca-certificates \ && rm -rf /var/lib/apt/lists/* # Copy bash scripts @@ -30,4 +34,8 @@ COPY --from=build /build/bridge /protonmail/ COPY --from=build /build/proton-bridge /protonmail/ COPY --from=build /build/vault-editor /protonmail/ +# Prevent the bridge's built-in auto-updater from replacing the container binary at runtime. +# Version management is handled externally via the update-check workflow. +RUN chmod -w /protonmail/bridge /protonmail/proton-bridge /protonmail/vault-editor + ENTRYPOINT ["bash", "/protonmail/entrypoint.sh"] diff --git a/build/entrypoint.sh b/build/entrypoint.sh index 1931087..3dc5800 100644 --- a/build/entrypoint.sh +++ b/build/entrypoint.sh @@ -2,13 +2,19 @@ set -ex +# Workaround for stale gpg-agent socket causing auth failures on restart +# Cleans up leftover sockets in the GPG home directory +if [ -d /root/.gnupg ]; then + rm -f /root/.gnupg/S.gpg-agent* +fi + # Initialize if [[ $1 == init ]]; then # Initialize pass gpg --generate-key --batch /protonmail/gpgparams pass init pass-key - + # Kill the other instance as only one can be running at a time. # This allows users to run entrypoint init inside a running conainter # which is useful in a k8s environment. @@ -30,6 +36,13 @@ else # Fake a terminal, so it does not quit because of EOF... rm -f faketty mkfifo faketty - cat faketty | /protonmail/proton-bridge --cli $@ + + # Keep faketty open indefinitely (more stable than cat pipe over long uptimes) + sleep infinity > faketty & + + # Start bridge reading from faketty; wait so container exits with bridge's exit code + /protonmail/proton-bridge --cli $@ < faketty & + wait $! + exit $? fi diff --git a/deb/Dockerfile b/deb/Dockerfile deleted file mode 100644 index a0d8e2c..0000000 --- a/deb/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -### The Deb install is just a repack of the official ProtonMail Bridge deb package with less dependencies. -### I recommend you don't use this. It's here for legacy reasons. - -FROM debian:sid-slim AS build - -COPY install.sh PACKAGE / -RUN apt-get update && apt-get install -y wget binutils - -# Repack deb (removes unnecessary dependencies and produces /protonmail.deb) -RUN bash /install.sh - -FROM debian:sid-slim -LABEL maintainer="Simon Felding " - -EXPOSE 25/tcp -EXPOSE 143/tcp - -WORKDIR /protonmail - -# Copy bash scripts -COPY gpgparams entrypoint.sh PACKAGE /protonmail/ -COPY --from=build /protonmail.deb /tmp/protonmail.deb - -RUN apt-get update \ - && apt-get install -y --no-install-recommends /tmp/protonmail.deb socat pass libsecret-1-0 ca-certificates procps \ - && rm -rf /var/lib/apt/lists/* - -CMD ["bash", "/protonmail/entrypoint.sh"] diff --git a/deb/PACKAGE b/deb/PACKAGE deleted file mode 100644 index 6d4eacd..0000000 --- a/deb/PACKAGE +++ /dev/null @@ -1 +0,0 @@ -https://github.com/ProtonMail/proton-bridge/releases/download/v3.22.0/protonmail-bridge_3.22.0-1_amd64.deb \ No newline at end of file diff --git a/deb/entrypoint.sh b/deb/entrypoint.sh deleted file mode 100644 index 13637e5..0000000 --- a/deb/entrypoint.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -set -ex - -# Initialize -if [[ $1 == init ]]; then - - # # Parse parameters - # TFP="" # Default empty two factor passcode - # shift # skip `init` - # while [[ $# -gt 0 ]]; do - # key="$1" - # case $key in - # -u|--username) - # USERNAME="$2" - # ;; - # -p|--password) - # PASSWORD="$2" - # ;; - # -t|--twofactor) - # TWOFACTOR="$2" - # ;; - # esac - # shift - # shift - # done - - # Initialize pass - gpg --generate-key --batch /protonmail/gpgparams - pass init pass-key - - # Login - protonmail-bridge --cli - -else - - # socat will make the conn appear to come from 127.0.0.1 - # ProtonMail Bridge currently expects that. - # It also allows us to bind to the real ports :) - socat TCP-LISTEN:25,fork TCP:127.0.0.1:1025 & - socat TCP-LISTEN:143,fork TCP:127.0.0.1:1143 & - - # Start protonmail - # Fake a terminal, so it does not quit because of EOF... - rm -f faketty - mkfifo faketty - cat faketty | protonmail-bridge --cli - -fi diff --git a/deb/gpgparams b/deb/gpgparams deleted file mode 100644 index 355568e..0000000 --- a/deb/gpgparams +++ /dev/null @@ -1,8 +0,0 @@ -%no-protection -%echo Generating a basic OpenPGP key -Key-Type: RSA -Key-Length: 2048 -Name-Real: pass-key -Expire-Date: 0 -%commit -%echo done diff --git a/deb/install.sh b/deb/install.sh deleted file mode 100644 index 9593725..0000000 --- a/deb/install.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -set -ex - -# Repack deb (remove unnecessary dependencies) -mkdir deb -wget -i /PACKAGE -O /deb/protonmail.deb -cd deb -ar x -v protonmail.deb -mkdir control -tar zxvf control.tar.gz -C control -sed -i "s/^Depends: .*$/Depends: libgl1, libc6, libsecret-1-0, libstdc++6, libgcc1/" control/control -cd control -tar zcvf ../control.tar.gz . -cd ../ - -ar rcs -v /protonmail.deb debian-binary control.tar.gz data.tar.gz