diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index cb20661..f8bcb2e 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -2,94 +2,212 @@ name: build from source on: push: - branches: - - master - - dev paths: - .github/workflows/build.yaml - build/* - - deb/* + - VERSION pull_request: paths: - .github/workflows/build.yaml - build/* - - deb/* workflow_dispatch: env: - DOCKER_REPO: shenxn/protonmail-bridge + GHCR_REPO: shenxn/protonmail-bridge-docker + DOCKERHUB_REPO: shenxn/protonmail-bridge DOCKER_REPO_DEV: ghcr.io/shenxn/protonmail-bridge-dev PLATFORMS: linux/amd64,linux/arm64/v8,linux/arm/v7,linux/riscv64 jobs: - build: + test: runs-on: ubuntu-latest - services: - registry: - image: registry:2 - ports: - - 5000:5000 + if: github.event_name == 'pull_request' steps: - - name: Checkout - uses: actions/checkout@master + - name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + - name: Set version id: version - run: echo "::set-output name=version::`cat build/VERSION`" - - 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 + run: echo "::set-output name=version::`cat VERSION`" + - name: Docker meta - id: docker_meta - uses: crazy-max/ghaction-docker-meta@v1 + id: meta + uses: docker/metadata-action@v5 with: - images: ${{ steps.repo.outputs.repo }} - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + images: | + ${{ env.DOCKERHUB_REPO }} + ${{ env.GHCR_REPO }} + - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 with: driver-opts: network=host - - name: Build image without push to registry - uses: docker/build-push-action@v2 + + - name: Build and push by digest + id: build + uses: docker/build-push-action@v6 with: + labels: ${{ steps.meta.outputs.labels }} + outputs: type=image,"name=${{ env.DOCKERHUB_REPO }},${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=false context: ./build file: ./build/Dockerfile - platforms: ${{ env.PLATFORMS }} - push: true - tags: localhost:5000/protonmail-bridge:latest + tags: localbuild/protonmail-bridge:test + build-args: | + version="${{ steps.version.outputs.version }}" - name: Scan image id: scan - uses: anchore/scan-action@v2 + uses: anchore/scan-action@v6 with: - image: localhost:5000/protonmail-bridge:latest + image: localbuild/protonmail-bridge:test fail-build: true severity-cutoff: critical - acs-report-enable: true - name: Upload Anchore scan SARIF report - uses: github/codeql-action/upload-sarif@v1 + 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' && github.ref == 'refs/heads/master' }} + + build: + runs-on: ubuntu-latest + if: github.event_name == 'push' && github.ref == 'refs/heads/master' + strategy: + fail-fast: false + matrix: + platform: + - linux/amd64 + - linux/arm64/v8 + - linux/arm/v7 + - linux/riscv64 + steps: + - name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + + - name: Set version + id: version + run: echo "::set-output name=version::`cat VERSION`" + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.DOCKERHUB_REPO }} + ${{ env.GHCR_REPO }} + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push by digest + id: build + 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=true + context: ./build + file: ./build/Dockerfile + tags: build,{{ steps.version.outputs.version }}-build + provenance: true + sbom: true + build-args: | + version="${{ steps.version.outputs.version }}" + + - name: Export digest + run: | + mkdir -p ${{ runner.temp }}/digests + digest="${{ steps.build.outputs.digest }}" + touch "${{ runner.temp }}/digests/${digest#sha256:}" + + - name: Scan image + id: scan + uses: anchore/scan-action@v6 + with: + image: ${{ env.DOCKERHUB_REPO }}/protonmail-bridge:${{ steps.build.outputs.digest }} + fail-build: true + severity-cutoff: critical + - name: Upload Anchore scan SARIF report + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: ${{ steps.scan.outputs.sarif }} + + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ env.PLATFORM_PAIR }} + path: ${{ runner.temp }}/digests/* + if-no-files-found: error + retention-days: 1 + + + merge: + runs-on: ubuntu-latest + needs: + - build + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: ${{ runner.temp }}/digests + pattern: digests-* + merge-multiple: true + + - name: Login to Docker Hub + uses: docker/login-action@v3 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' && github.ref == 'refs/heads/dev' }} + + - name: Login to GHCR + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.CR_PAT }} - - name: Push image - uses: docker/build-push-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 with: - context: ./build - file: ./build/Dockerfile - platforms: ${{ env.PLATFORMS }} + driver-opts: network=host + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.DOCKERHUB_REPO }} + ${{ env.GHCR_REPO }} tags: | - ${{ steps.repo.outputs.repo }}:build - ${{ steps.repo.outputs.repo }}:${{ steps.version.outputs.version }}-build - labels: ${{ steps.docker_meta.outputs.labels }} - push: ${{ github.event_name != 'pull_request' }} + type=raw,enable=true,value=${{ steps.version.outputs.version }}-build + type=raw,enable=true,suffix=,value=build + + - 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: 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 }} diff --git a/.github/workflows/deb.yaml b/.github/workflows/deb.yaml index a529c66..826b9ce 100644 --- a/.github/workflows/deb.yaml +++ b/.github/workflows/deb.yaml @@ -25,7 +25,7 @@ jobs: uses: actions/checkout@master - name: Set version id: version - run: echo "::set-output name=version::`cat deb/VERSION`" + run: echo "::set-output name=version::`cat VERSION`" - 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 @@ -57,13 +57,13 @@ jobs: sarif_file: ${{ steps.scan.outputs.sarif }} - name: Login to DockerHub uses: docker/login-action@v1 - if: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/master' }} + 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' && github.ref == 'refs/heads/dev' }} + if: ${{ github.event_name != 'pull_request' }} with: registry: ghcr.io username: ${{ github.repository_owner }} diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..7ccd8d4 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +3.16.0 \ No newline at end of file diff --git a/build/Dockerfile b/build/Dockerfile index a54e04a..7b1427f 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -2,12 +2,12 @@ FROM debian:sid-slim AS build # Install dependencies -RUN apt-get update && apt-get install -y git golang build-essential libsecret-1-dev +RUN apt-get update && apt-get install -y golang build-essential libsecret-1-dev # Build +ADD https://github.com/ProtonMail/proton-bridge.git#{version} /build/ WORKDIR /build/ -COPY build.sh VERSION /build/ -RUN bash build.sh +RUN make build-nogui vault-editor FROM debian:sid-slim LABEL maintainer="Simon Felding " @@ -24,8 +24,8 @@ RUN apt-get update \ COPY gpgparams entrypoint.sh /protonmail/ # Copy protonmail -COPY --from=build /build/proton-bridge/bridge /protonmail/ -COPY --from=build /build/proton-bridge/proton-bridge /protonmail/ -COPY --from=build /build/proton-bridge/vault-editor /protonmail/ +COPY --from=build /build/bridge /protonmail/ +COPY --from=build /build/proton-bridge /protonmail/ +COPY --from=build /build/vault-editor /protonmail/ ENTRYPOINT ["bash", "/protonmail/entrypoint.sh"] diff --git a/build/VERSION b/build/VERSION deleted file mode 100644 index 209f579..0000000 --- a/build/VERSION +++ /dev/null @@ -1 +0,0 @@ -3.19.0 \ No newline at end of file diff --git a/build/build.sh b/build/build.sh deleted file mode 100644 index 0b27550..0000000 --- a/build/build.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -set -ex - -VERSION=`cat VERSION` - -# Clone new code -git clone https://github.com/ProtonMail/proton-bridge.git -cd proton-bridge -git checkout v$VERSION - -# Build -make build-nogui vault-editor diff --git a/deb/Dockerfile b/deb/Dockerfile index 8ef00b6..a8cdaa5 100644 --- a/deb/Dockerfile +++ b/deb/Dockerfile @@ -1,5 +1,16 @@ +### 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 RELEASE install.sh / +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="Xiaonan Shen " +LABEL maintainer="Simon Felding " EXPOSE 25/tcp EXPOSE 143/tcp @@ -7,16 +18,11 @@ EXPOSE 143/tcp WORKDIR /protonmail # Copy bash scripts -COPY gpgparams install.sh entrypoint.sh VERSION /protonmail/ +COPY gpgparams entrypoint.sh RELEASE /protonmail/ +COPY --from=build /protonmail.deb /tmp/protonmail.deb RUN apt-get update \ - && apt-get install -y --no-install-recommends socat pass procps libsecret-1-0 ca-certificates \ + && apt-get install -y --no-install-recommends /tmp/protonmail.deb socat pass libsecret-1-0 ca-certificates \ && rm -rf /var/lib/apt/lists/* -# Copy bash scripts -COPY gpgparams entrypoint.sh /protonmail/ - -# Install dependencies and protonmail bridge -RUN bash install.sh - -ENTRYPOINT ["bash", "/protonmail/entrypoint.sh"] +CMD ["bash", "/protonmail/entrypoint.sh"] diff --git a/deb/PACKAGE b/deb/PACKAGE new file mode 100644 index 0000000..8ec4123 --- /dev/null +++ b/deb/PACKAGE @@ -0,0 +1 @@ +https://github.com/ProtonMail/proton-bridge/releases/download/v3.16.0/protonmail-bridge_3.16.0-1_amd64.deb \ No newline at end of file diff --git a/deb/VERSION b/deb/VERSION deleted file mode 100644 index e177934..0000000 --- a/deb/VERSION +++ /dev/null @@ -1 +0,0 @@ -3.19.0-1 \ No newline at end of file diff --git a/deb/install.sh b/deb/install.sh index dbe3eb5..b71fea7 100644 --- a/deb/install.sh +++ b/deb/install.sh @@ -1,36 +1,16 @@ #!/bin/bash - set -ex -VERSION=`cat VERSION` -DEB_FILE=protonmail-bridge_${VERSION}_amd64.deb - -# Install dependents -apt-get update -apt-get install -y --no-install-recommends socat pass ca-certificates - -# Build time dependencies -apt-get install -y wget binutils xz-utils - # Repack deb (remove unnecessary dependencies) mkdir deb +wget -i "$RELEASE" -O /deb/protonmail.deb cd deb -wget -q https://protonmail.com/download/bridge/${DEB_FILE} -ar x -v ${DEB_FILE} +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 ${DEB_FILE} debian-binary control.tar.gz data.tar.gz -cd ../ -# Install protonmail bridge -apt-get install -y --no-install-recommends ./deb/${DEB_FILE} - -# Cleanup -apt-get purge -y wget binutils xz-utils -apt-get autoremove -y -rm -rf /var/lib/apt/lists/* -rm -rf deb +ar rcs -v /protonmail.deb debian-binary control.tar.gz data.tar.gz diff --git a/update-check.py b/update-check.py index e8d5381..c5ddb9c 100644 --- a/update-check.py +++ b/update-check.py @@ -1,64 +1,31 @@ -import sys -import os -import requests -import json -import re +import requests, os -is_pull_request = sys.argv[1] == "true" -print(f"is_pull_request={is_pull_request}") +def git(command): + return os.system(f"git {command}") +release = requests.get("https://api.github.com/repos/protonmail/proton-bridge/releases/latest").json() +version = release['tag_name'] +deb = [asset for asset in release ['assets'] if asset['name'].endswith('.deb')][0]['browser_download_url'] -def check_version(directory, new_version): - print(f"Checking version for {directory}") +print(f"Latest release is: {version}") - if not new_version: - print("Failed to get new version. Exiting.") - exit(1) +with open("VERSION", 'w') as f: + f.write(version) - with open(f"{directory}/VERSION", "r") as f: - old_version = f.read().rstrip() - - print(f"Up-to-date version {new_version}") - print(f"Current version: {old_version}") +with open("deb/PACKAGE", 'w') as f: + f.write(deb) - if old_version != new_version: - print(f"New release found: {new_version}") +git("config --local user.name 'GitHub Actions'") +git("config --local user.email 'actions@github.com'") - # bump up to new release - with open(f"{directory}/VERSION", "w") as f: - f.write(new_version) - # commit - result = os.system(f"git config --local user.email 'actions@github.com' \ - && git config --local user.name 'GitHub Actions' \ - && git add {directory}/VERSION \ - && git commit -m 'Bump {directory} version to {new_version}'") - if result != 0: - print("Failed to commit the bump. Exiting") - exit(1) - if is_pull_request: - print("Action triggered by pull request. Do not push.") - else: - result = os.system("git push") - if result != 0: - print("Failed to push. Exiting") - exit(1) - else: - print(f"Already newest version {old_version}") +git("add -A") +if git("diff --cached --quiet") == 0: # Returns 0 if there are no changes + print("Version didn't change") + exit(1) -# check deb version -response = requests.get("https://protonmail.com/download/current_version_linux.json") -content = json.loads(response.content) -version = re.match(".*_([0-9.-]+)_amd64\.deb", content["DebFile"]).group(1) -check_version("deb", version) +git(f"commit -m 'Bump version to {version}'") - -# check build version -response = requests.get( - "https://api.github.com/repos/ProtonMail/proton-bridge/tags", - headers={"Accept": "application/vnd.github.v3+json"}, - ) -tags = json.loads(response.content) -version_re = re.compile("v\d+\.\d+\.\d+") -releases = [tag["name"][1:] for tag in tags if version_re.match(tag["name"])] -check_version("build", releases[0]) +if git("push") != 0: + print("Git push failed!") + exit(1)