Build patch-improve-musl-build #127
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| name: Build and Push Docker Image | |
| run-name: Build ${{ github.ref_name }} | |
| # | |
| # "Continuous Integration workflow for building, the project." | |
| # | |
| # Jobs included: | |
| # - build: building the image | |
| # | |
| # Required Secrets: | |
| # NONE | |
| on: # yamllint disable-line rule:truthy | |
| push: | |
| branches: ["**"] # matches any branch | |
| tags: ["v*"] | |
| pull_request: | |
| branches: ["**"] | |
| # Declare default permissions as none. | |
| permissions: {} | |
| jobs: | |
| seed: | |
| permissions: | |
| actions: read | |
| contents: read | |
| packages: none | |
| pull-requests: read | |
| runs-on: macos-latest # Has FreeBSD date (with -j and -f [format] options) | |
| outputs: | |
| timestamp: ${{ steps.output_time.outputs.bootstrap-timestamp }} | |
| mitl-timestamp: ${{ steps.output_time.outputs.mitl-timestamp }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 0 | |
| submodules: false | |
| - id: output_time | |
| name: Get Git commit timestamps | |
| shell: bash | |
| run: | | |
| printf "%s\n" "::group::bootstrap-MITL-env" | |
| printf "bootstrap-timestamp=%s\n" $(git log -1 --pretty=%ct) >> "$GITHUB_OUTPUT" | |
| printf "TIMESTAMP=%s\n" $(git log -1 --pretty=%ct) >> "$GITHUB_ENV" | |
| printf "mitl-timestamp=%s %s\n" $(date -j -f "%s" "$(git log -1 --pretty=%ct)" "+%C%y-%d-%m %H:%M:%S") >> "$GITHUB_OUTPUT" | |
| printf "%s %s\n" "MITL-Bootstrap will be synced at time of:" $(date -j -f "%s" "$(git log -1 --pretty=%ct)" "+%C%y-%d-%m %H:%M:%S") | |
| printf "%s\n" "::endgroup::" | |
| build: | |
| permissions: | |
| actions: read | |
| contents: read | |
| statuses: write | |
| packages: write | |
| pull-requests: read | |
| security-events: none | |
| needs: seed | |
| strategy: | |
| matrix: | |
| include: | |
| - architecture: amd64 | |
| runner: ubuntu-latest | |
| - architecture: arm64 | |
| runner: ubuntu-24.04-arm | |
| - architecture: arm | |
| runner: ubuntu-24.04-arm | |
| runs-on: ${{ matrix.runner }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 0 | |
| submodules: false | |
| - name: Prepare | |
| id: prep_output | |
| run: | | |
| platform=linux/${{ matrix.architecture }} | |
| echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV | |
| if [ "${{ matrix.architecture }}" == "amd64" ]; then | |
| echo "TARGET_TRIPLE=x86_64-generic-none-musl" >> $GITHUB_ENV | |
| echo "target-triple=x86_64-generic-none-musl" >> "$GITHUB_OUTPUT" | |
| echo "HOST_TRIPLE=x86_64-alpine-linux-musl" >> $GITHUB_ENV | |
| echo "host-triple=x86_64-alpine-linux-musl" >> "$GITHUB_OUTPUT" | |
| echo "MUSL_LDLIB=ld-musl-x86_64.so.1" >> $GITHUB_ENV | |
| echo "musl-ldlib=ld-musl-x86_64.so.1" >> "$GITHUB_OUTPUT" | |
| elif [ "${{ matrix.architecture }}" == "arm64" ]; then | |
| echo "TARGET_TRIPLE=aarch64-generic-none-musl" >> $GITHUB_ENV | |
| echo "target-triple=aarch64-generic-none-musl" >> "$GITHUB_OUTPUT" | |
| echo "HOST_TRIPLE=aarch64-alpine-linux-musl" >> $GITHUB_ENV | |
| echo "host-triple=aarch64-alpine-linux-musl" >> "$GITHUB_OUTPUT" | |
| echo "MUSL_LDLIB=ld-musl-aarch64.so.1" >> $GITHUB_ENV | |
| echo "musl-ldlib=ld-musl-aarch64.so.1" >> "$GITHUB_OUTPUT" | |
| elif [ "${{ matrix.architecture }}" == "arm" ]; then | |
| echo "TARGET_TRIPLE=arm-generic-none-musleabi" >> $GITHUB_ENV | |
| echo "target-triple=arm-generic-none-musleabi" >> "$GITHUB_OUTPUT" | |
| echo "HOST_TRIPLE=arm-alpine-linux-musleabi" >> $GITHUB_ENV | |
| echo "host-triple=arm-alpine-linux-musleabi" >> "$GITHUB_OUTPUT" | |
| echo "MUSL_LDLIB=ld-musl-armhf.so.1" >> $GITHUB_ENV | |
| echo "musl-ldlib=ld-musl-armhf.so.1" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "Unsupported architecture: ${{ matrix.architecture }}" | |
| exit 1 | |
| fi | |
| # QEMU setup only for armv7 emulation | |
| - name: Set up QEMU (for armv7) | |
| if: ${{ matrix.architecture == 'arm' }} | |
| uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 | |
| with: | |
| platforms: linux/${{ matrix.architecture }} | |
| cleanup: true | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 | |
| with: | |
| context: git | |
| images: ghcr.io/reactive-firewall/mitl-bootstrap | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=pr | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=sha | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ github.token }} | |
| logout: true | |
| - name: Build and push Docker image | |
| id: build | |
| uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 | |
| with: | |
| context: . | |
| file: dockerfile | |
| labels: ${{ steps.meta.outputs.labels }} | |
| tags: ghcr.io/reactive-firewall/mitl-bootstrap | |
| platforms: linux/${{ matrix.architecture }} | |
| build-args: | | |
| TOYBOX_VERSION=0.8.12 | |
| TARGETARCH=${{ matrix.architecture }} | |
| TARGET_TRIPLE=${{ steps.prep_output.outputs.target-triple }} | |
| HOST_TRIPLE=${{ steps.prep_output.outputs.host-triple }} | |
| MUSL_VER=1.2.5 | |
| MUSL_LDLIB=${{ steps.prep_output.outputs.musl-ldlib }} | |
| MITL_DATE_EPOCH=${{ needs.seed.outputs.mitl-timestamp }} | |
| cache-from: type=local,src=/tmp/.buildx-cache | |
| cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max | |
| attests: | | |
| type=sbom | |
| type=provenance | |
| sbom: true | |
| provenance: mode=max | |
| push: true | |
| annotations: | | |
| index.org.opencontainers.image.title=MITL-bootstrap | |
| index.org.opencontainers.image.authors=mitl-maintainers@users.noreply.github.com | |
| index.org.opencontainers.image.description=Multi-arch MITL Bootstrap image | |
| index.org.opencontainers.image.vendor=individual | |
| index.org.opencontainers.image.licenses="MIT" | |
| outputs: type=image,push-by-digest=true,name-canonical=true,push=true,annotation-index.org.opencontainers.image.description=Multi-arch MITL Bootstrap image ${{ matrix.architecture }} | |
| env: | |
| TARGET_TRIPLE: ${{ steps.prep_output.outputs.target-triple }} | |
| HOST_TRIPLE: ${{ steps.prep_output.outputs.host-triple }} | |
| MUSL_LDLIB: ${{ steps.prep_output.outputs.musl-ldlib }} | |
| SOURCE_DATE_EPOCH: ${{ needs.seed.outputs.timestamp }} | |
| MITL_DATE_EPOCH: ${{ needs.seed.outputs.mitl-timestamp }} | |
| TOYBOX_VERSION: "0.8.12" | |
| MUSL_VER: "1.2.5" | |
| TARGETARCH: ${{ matrix.architecture }} | |
| - name: Export digest | |
| run: | | |
| mkdir -p ${{ runner.temp }}/digests | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "${{ runner.temp }}/digests/${digest#sha256:}" | |
| - name: Logout from Docker Hub | |
| run: docker logout | |
| - name: Upload digest | |
| uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 | |
| with: | |
| name: digests-${{ env.PLATFORM_PAIR }} | |
| path: ${{ runner.temp }}/digests/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| merge: | |
| permissions: | |
| actions: read | |
| contents: read | |
| statuses: write | |
| packages: write | |
| pull-requests: read | |
| security-events: none | |
| runs-on: ubuntu-latest | |
| needs: build | |
| outputs: | |
| merge_version: ${{ steps.meta.outputs.version }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 0 | |
| submodules: false | |
| - name: Download digests | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| path: ${{ runner.temp }}/digests | |
| pattern: digests-* | |
| merge-multiple: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ github.token }} | |
| logout: true | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 | |
| with: | |
| context: git | |
| images: ghcr.io/reactive-firewall/mitl-bootstrap | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=pr | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=sha | |
| env: | |
| SOURCE_DATE_EPOCH: ${{ needs.seed.outputs.timestamp }} | |
| - name: Create manifest list and push | |
| working-directory: ${{ runner.temp }}/digests | |
| env: | |
| SOURCE_DATE_EPOCH: ${{ needs.seed.outputs.timestamp }} | |
| run: | | |
| docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
| $(printf 'ghcr.io/reactive-firewall/mitl-bootstrap@sha256:%s ' *) | |
| - name: Inspect image | |
| run: | | |
| docker buildx imagetools inspect ghcr.io/reactive-firewall/mitl-bootstrap:${{ steps.meta.outputs.version }} | |
| - name: Ensure image is pullable locally | |
| run: | | |
| # ensure the platform-specific image manifest is present locally for Syft/Grype | |
| docker pull ghcr.io/reactive-firewall/mitl-bootstrap:${{ steps.meta.outputs.version }} | |
| - name: Pull Syft and Grype images | |
| run: | | |
| # ensure the Syft and Grype images are available | |
| docker pull anchore/syft:v1.31.0 | |
| docker pull anchore/grype:v0.98.0 | |
| - name: Generate SBOM (Syft) for this architecture | |
| env: | |
| IMAGE: ghcr.io/reactive-firewall/mitl-bootstrap:${{ steps.meta.outputs.version }} | |
| run: | | |
| SYFT_IMG=anchore/syft:v1.31.0 # adjust version if desired | |
| docker run --rm \ | |
| -v /var/run/docker.sock:/var/run/docker.sock \ | |
| $SYFT_IMG ${IMAGE} -o spdx-json > sbom.json | |
| - name: Scan image with Grype (vulnerability) and export results | |
| env: | |
| IMAGE: ghcr.io/reactive-firewall/mitl-bootstrap:${{ steps.meta.outputs.version }} | |
| run: | | |
| GRYPE_IMG=anchore/grype:v0.98.0 | |
| # run grype against the image and produce JSON output | |
| docker run --rm \ | |
| -v /var/run/docker.sock:/var/run/docker.sock \ | |
| $GRYPE_IMG ${IMAGE} -o json > grype.json || true | |
| # (grype exits non-zero on findings; keep the job green by allowing non-zero) | |
| - name: Upload per-arch SBOM and Grype report | |
| uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 | |
| with: | |
| name: sbom-and-scan | |
| path: | | |
| sbom.json | |
| - name: Logout from Docker Hub | |
| run: docker logout | |
| test: | |
| permissions: | |
| actions: read | |
| contents: read | |
| statuses: write | |
| packages: read | |
| pull-requests: read | |
| security-events: none | |
| needs: merge | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| shell: bash | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 0 | |
| submodules: false | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ github.token }} | |
| logout: true | |
| - name: Pull local copy for test | |
| run: | | |
| docker pull ghcr.io/reactive-firewall/mitl-bootstrap:${{ needs.merge.outputs.merge_version }} | |
| - name: Run Docker test container | |
| id: run_container | |
| shell: bash | |
| run: | | |
| docker run -d --name test-container ghcr.io/reactive-firewall/mitl-bootstrap:${{ needs.merge.outputs.merge_version }} /bin/bash -c "while true; do sleep 30; done" | |
| printf "::group::%s\n" "Testing" | |
| docker exec test-container /bin/sh -c "toybox sh -c 'echo Toybox shell is working'" || exit 1 | |
| docker exec test-container /bin/bash --version | |
| docker exec test-container /bin/bash -c "toybox bash --version" | |
| docker exec test-container /bin/bash -c "printf '%s\n' 'Toybox printf is working'" || exit 1 | |
| if docker exec test-container /bin/bash -c "which gcc"; then | |
| printf "%s\n" "gcc command is present in the image." | |
| exit 1 | |
| else | |
| printf "%s\n" "gcc command is not present in the image." | |
| fi | |
| if docker exec test-container /bin/bash -c "which g++"; then | |
| printf "%s\n" "g++ command is present in the image." | |
| exit 1 | |
| else | |
| printf "%s\n" "g++ command is not present in the image." | |
| fi | |
| if docker exec test-container /bin/bash -c "which gunzip"; then | |
| printf "%s\n" "gunzip command is present in the image." | |
| exit 1 | |
| else | |
| printf "%s\n" "gunzip command is not present in the image." | |
| fi | |
| for REQ_CMD in "bash" "basename" "cat" "chgrp" "chmod" "chown" "cp" "date" "dirname" "find" "grep" "head" "mkdir" "mv" "rm" "sed" "sh" "sha256sum" "sha512sum" "true" "false" ; do | |
| if docker exec test-container /bin/bash -c "which ${REQ_CMD}"; then | |
| printf "%s\n" "${REQ_CMD:-unknown} command is present in the image." ; | |
| printf "%s\n" "${REQ_CMD:-unknown} command is configured in the path." ; | |
| else | |
| if docker exec test-container /bin/bash -c "find / -type f -iname ${REQ_CMD} 2>/dev/null"; then | |
| printf "%s\n" "${REQ_CMD:-unknown} command is present in the image." | |
| printf "%s\n" "${REQ_CMD:-unknown} command is not configured in the path." | |
| else | |
| printf "%s\n" "${REQ_CMD:-unknown} command is not present in the image." | |
| exit 2 ; | |
| fi ; | |
| exit 1 ; | |
| fi ; | |
| done ; | |
| printf "::endgroup::\n\n" | |
| for REQ_PATH in "/bin" "/usr/" "/sbin" "/lib" "/usr/bin" "/usr/local/bin" "/usr/local/bin" "/usr/local/sbin" "/usr/lib" "/usr/libexec" "/etc" "/var" "/" ; do | |
| printf "::group::%s\n" "${REQ_PATH}" | |
| if docker exec test-container /bin/bash -c "test -d ${REQ_PATH}"; then | |
| printf "%s\n" "${REQ_PATH:-unknown} path is present in the image." ; | |
| printf "%s\n" "${REQ_PATH:-unknown} path is a directory in the image." ; | |
| printf "::endgroup::\n" | |
| printf "::group::%s\n" "Contents" | |
| docker exec test-container /bin/bash -c "ls -la ${REQ_PATH}" ; | |
| printf "::endgroup::\n" | |
| else | |
| if docker exec test-container /bin/bash -c "test -e ${REQ_PATH}"; then | |
| printf "%s\n" "${REQ_PATH:-unknown} path is present in the image." ; | |
| printf "%s\n" "${REQ_PATH:-unknown} path is not a directory in the image." ; | |
| printf "::endgroup::\n" | |
| printf "::group::%s\n" "Stats" | |
| docker exec test-container /bin/bash -c "ls -la ${REQ_PATH}" ; | |
| printf "::endgroup::\n" | |
| else | |
| printf "%s\n" "${REQ_PATH:-unknown} path is not present in the image." | |
| printf "::endgroup::\n" | |
| # TODO: abort on fail | |
| # exit 2 ; | |
| fi ; | |
| # TODO: abort on fail | |
| fi ; | |
| done ; | |
| - name: Clean up | |
| run: | | |
| docker stop test-container || true ; | |
| docker rm -f test-container | |
| - name: Logout from Docker Hub | |
| run: docker logout |