name: Build on: push: branches: [main] tags: - "v*" # Only run for pull requests if relevant files were changed pull_request: branches: [main] paths: - Dockerfile - docker-bake.hcl - .github/workflows/build.yaml concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true env: CARGO_TERM_COLOR: always CARGO_NET_GIT_FETCH_WITH_CLI: "true" SCCACHE_GHA_ENABLED: "true" RUSTC_WRAPPER: "sccache" IMAGE: ghcr.io/element-hq/matrix-authentication-service IMAGE_SYN2MAS: ghcr.io/element-hq/matrix-authentication-service/syn2mas BUILDCACHE: ghcr.io/element-hq/matrix-authentication-service/buildcache DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index jobs: build-binaries: name: Build binaries runs-on: ubuntu-22.04 permissions: contents: read steps: - name: Checkout the code uses: actions/checkout@v4.1.7 - name: Setup OPA uses: open-policy-agent/setup-opa@v2.2.0 with: version: 0.64.1 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: targets: | x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu - name: Setup sccache uses: mozilla-actions/sccache-action@v0.0.5 - name: Install zig uses: goto-bus-stop/setup-zig@v2 with: version: 0.13.0 - name: Install cargo-zigbuild run: curl -L https://github.com/rust-cross/cargo-zigbuild/releases/download/v0.19.1/cargo-zigbuild-v0.19.1.x86_64-unknown-linux-musl.tar.gz | tar -z -x -C /usr/local/bin - name: Install frontend Node uses: actions/setup-node@v4.0.3 with: node-version: 20 - name: Install frontend Node dependencies working-directory: ./frontend run: npm ci - name: Build frontend working-directory: ./frontend run: npm run build - name: Build policies working-directory: ./policies run: make - name: Build the binary run: | cargo zigbuild \ --release \ --target x86_64-unknown-linux-gnu.2.17 \ --target aarch64-unknown-linux-gnu.2.17 \ --no-default-features \ --features dist \ -p mas-cli - name: Create one archive per architecture run: | for arch in x86_64 aarch64; do # Create one directory per architecture mkdir -p dist/${arch}/share/ # Copy the artifacts to the right place cp policies/policy.wasm dist/${arch}/share/policy.wasm cp frontend/dist/manifest.json dist/${arch}/share/manifest.json cp -r frontend/dist/ dist/${arch}/share/assets cp -r templates/ dist/${arch}/share/templates cp -r translations/ dist/${arch}/share/translations cp LICENSE dist/${arch}/LICENSE chmod -R u=rwX,go=rX dist/${arch}/ # Copy the binary to the right place cp target/${arch}-unknown-linux-gnu/release/mas-cli dist/${arch}/ chmod u=rwx,go=rx dist/${arch}/mas-cli # Create the archive tar -czvf mas-cli-${arch}-linux.tar.gz --owner=0 --group=0 -C dist/${arch}/ . done - name: Upload the artifacts uses: actions/upload-artifact@v4.4.0 with: name: binaries path: | mas-cli-aarch64-linux.tar.gz mas-cli-x86_64-linux.tar.gz build-image: name: Build and push Docker image runs-on: ubuntu-latest outputs: metadata: ${{ steps.output.outputs.metadata }} permissions: contents: read packages: write id-token: write steps: - name: Checkout the code uses: actions/checkout@v4.1.7 - name: Docker meta id: meta uses: docker/metadata-action@v5.5.1 with: images: "${{ env.IMAGE }}" bake-target: docker-metadata-action flavor: | latest=auto tags: | type=ref,event=branch type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}} type=sha - name: Docker meta (debug variant) id: meta-debug uses: docker/metadata-action@v5.5.1 with: images: "${{ env.IMAGE }}" bake-target: docker-metadata-action-debug flavor: | latest=auto suffix=-debug,onlatest=true tags: | type=ref,event=branch type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}} type=sha - name: Docker meta (syn2mas) id: meta-syn2mas uses: docker/metadata-action@v5.5.1 with: images: "${{ env.IMAGE_SYN2MAS }}" bake-target: docker-metadata-action-syn2mas flavor: | latest=auto tags: | type=ref,event=branch type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}} type=sha - name: Setup Cosign uses: sigstore/cosign-installer@v3.6.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3.6.1 with: buildkitd-config-inline: | [registry."docker.io"] mirrors = ["mirror.gcr.io"] - name: Login to GitHub Container Registry if: github.event_name != 'pull_request' uses: docker/login-action@v3.3.0 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} # For pull-requests, only read from the cache, do not try to push to the # cache or the image itself - name: Build uses: docker/bake-action@v5.7.0 if: github.event_name == 'pull_request' with: files: | docker-bake.hcl ${{ steps.meta.outputs.bake-file }} ${{ steps.meta-debug.outputs.bake-file }} ${{ steps.meta-syn2mas.outputs.bake-file }} set: | base.context=https://github.com/${{ github.repository }}.git#${{ github.ref }} syn2mas.context=https://github.com/${{ github.repository }}.git#${{ github.ref }}:tools/syn2mas/ base.cache-from=type=registry,ref=${{ env.BUILDCACHE }}:buildcache - name: Build and push id: bake uses: docker/bake-action@v5.7.0 if: github.event_name != 'pull_request' with: files: | docker-bake.hcl ${{ steps.meta.outputs.bake-file }} ${{ steps.meta-debug.outputs.bake-file }} ${{ steps.meta-syn2mas.outputs.bake-file }} set: | base.context=https://github.com/${{ github.repository }}.git#${{ github.ref }} syn2mas.context=https://github.com/${{ github.repository }}.git#${{ github.ref }}:tools/syn2mas/ base.output=type=image,push=true base.cache-from=type=registry,ref=${{ env.BUILDCACHE }}:buildcache base.cache-to=type=registry,ref=${{ env.BUILDCACHE }}:buildcache,mode=max - name: Transform bake output # This transforms the ouput to an object which looks like this: # { reguar: { digest: "…", tags: ["…", "…"] }, debug: { digest: "…", tags: ["…"] }, … } id: output if: github.event_name != 'pull_request' run: | echo 'metadata<> $GITHUB_OUTPUT echo '${{ steps.bake.outputs.metadata }}' | jq -c 'with_entries(select(.value | (type == "object" and has("containerimage.digest")))) | map_values({ digest: .["containerimage.digest"], tags: (.["image.name"] | split(",")) })' >> $GITHUB_OUTPUT echo 'EOF' >> $GITHUB_OUTPUT - name: Sign the images with GitHub Actions provided token # Only sign on tags and on commits on main branch if: | github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') run: |- cosign sign --yes \ "${{ env.IMAGE }}@${{ fromJSON(steps.output.outputs.metadata).regular.digest }}" \ "${{ env.IMAGE }}@${{ fromJSON(steps.output.outputs.metadata).debug.digest }}" \ "${{ env.IMAGE_SYN2MAS }}@${{ fromJSON(steps.output.outputs.metadata).syn2mas.digest }}" syn2mas: name: Release syn2mas on NPM runs-on: ubuntu-latest permissions: contents: read id-token: write steps: - name: Checkout the code uses: actions/checkout@v4.1.7 - name: Install Node uses: actions/setup-node@v4.0.3 with: node-version-file: ./tools/syn2mas/.nvmrc - name: Install Node dependencies working-directory: ./tools/syn2mas run: npm ci - name: Publish uses: JS-DevTools/npm-publish@v3 with: package: ./tools/syn2mas token: ${{ secrets.NPM_TOKEN }} provenance: true dry-run: ${{ !startsWith(github.ref, 'refs/tags/') }} release: name: Release if: startsWith(github.ref, 'refs/tags/') runs-on: ubuntu-latest needs: - build-binaries - build-image - syn2mas steps: - name: Download the artifacts from the previous job uses: actions/download-artifact@v4 with: name: binaries path: artifacts - name: Prepare a release uses: softprops/action-gh-release@v2 with: body: | ### Docker image Regular image: - Digest: ``` ${{ env.IMAGE }}@${{ fromJSON(needs.build-image.outputs.metadata).regular.digest }} ``` - Tags: ``` ${{ join(fromJSON(needs.build-image.outputs.metadata).regular.tags, ' ') }} ``` Debug variant: - Digest: ``` ${{ env.IMAGE }}@${{ fromJSON(needs.build-image.outputs.metadata).debug.digest }} ``` - Tags: ``` ${{ join(fromJSON(needs.build-image.outputs.metadata).debug.tags, ' ') }} ``` `syn2mas` migration tool: - Digest: ``` ${{ env.IMAGE_SYN2MAS }}@${{ fromJSON(needs.build-image.outputs.metadata).syn2mas.digest }} ``` - Tags: ``` ${{ join(fromJSON(needs.build-image.outputs.metadata).syn2mas.tags, ' ') }} ``` files: | artifacts/mas-cli-aarch64-linux.tar.gz artifacts/mas-cli-x86_64-linux.tar.gz draft: true