commit 8d48dcc5fd40fffc2b3c89d99377d3f6122fbb72 Author: Mathias Beaulieu-Duncan Date: Mon Feb 2 00:39:04 2026 -0500 Initial minimal Flutter SDK image for web/WASM CI builds - Dockerfile based on debian:bookworm-slim with web-only Flutter SDK - Release pipeline with Docker Scout CVE scan, SBOM, and provenance - Scout PR pipeline with check-image gate - Daily update-check pipeline that auto-creates releases for new Flutter stable versions via Gitea API Co-Authored-By: Claude Opus 4.5 diff --git a/.gitea/workflows/publish.yaml b/.gitea/workflows/publish.yaml new file mode 100644 index 0000000..04f8e48 --- /dev/null +++ b/.gitea/workflows/publish.yaml @@ -0,0 +1,75 @@ +name: Build and Push Flutter SDK Image + +on: + release: + types: [published, prereleased] + +permissions: + contents: read + +env: + IMAGE_NAME: gpb-flutter-sdk-web + +jobs: + build-and-push: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Determine Tag Type + id: tag_type + run: | + if [[ "${{ github.event.release.prerelease }}" == "true" ]]; then + echo "tag=dev" >> $GITHUB_OUTPUT + else + echo "tag=latest" >> $GITHUB_OUTPUT + fi + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Registry + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_SVRNTY_USERNAME }} + password: ${{ secrets.DOCKERHUB_SVRNTY_ACCESS_TOKEN }} + + - name: Build image for Scout analysis + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64 + push: false + load: true + build-args: | + FLUTTER_VERSION=${{ github.event.release.tag_name }} + tags: ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.release.tag_name }} + + - name: Install Docker Scout + run: | + curl -fsSL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh -o install-scout.sh + sh install-scout.sh + + - name: Docker Scout CVE Scan + run: | + docker scout cves ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.release.tag_name }} --only-severity critical,high + + - name: Build and push with attestations + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64 + push: true + sbom: true + provenance: mode=max + build-args: | + FLUTTER_VERSION=${{ github.event.release.tag_name }} + tags: | + ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.release.tag_name }} + ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag_type.outputs.tag }} + labels: | + org.opencontainers.image.title=${{ env.IMAGE_NAME }} + org.opencontainers.image.description=Minimal Flutter SDK for Web/WASM CI builds + org.opencontainers.image.version=${{ github.event.release.tag_name }} + org.opencontainers.image.revision=${{ github.sha }} diff --git a/.gitea/workflows/scout.yaml b/.gitea/workflows/scout.yaml new file mode 100644 index 0000000..eb54796 --- /dev/null +++ b/.gitea/workflows/scout.yaml @@ -0,0 +1,70 @@ +name: Docker Scout Analysis + +on: + pull_request: + branches: ["**"] + +permissions: + contents: read + pull-requests: write + +env: + IMAGE_NAME: gpb-flutter-sdk-web + +jobs: + check-image: + runs-on: ubuntu-latest + outputs: + image_exists: ${{ steps.check.outputs.exists }} + steps: + - name: Log in to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_SVRNTY_USERNAME }} + password: ${{ secrets.DOCKERHUB_SVRNTY_ACCESS_TOKEN }} + + - name: Check if latest image exists + id: check + run: | + if docker manifest inspect ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:latest > /dev/null 2>&1; then + echo "exists=true" >> $GITHUB_OUTPUT + echo "Latest image found, Scout compare will run" + else + echo "exists=false" >> $GITHUB_OUTPUT + echo "No latest image found, skipping Scout compare (nothing to compare against)" + fi + + scout-amd64: + runs-on: ubuntu-latest + needs: check-image + if: needs.check-image.outputs.image_exists == 'true' + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_SVRNTY_USERNAME }} + password: ${{ secrets.DOCKERHUB_SVRNTY_ACCESS_TOKEN }} + + - name: Build amd64 image + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64 + push: false + load: true + tags: ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:pr-${{ github.event.pull_request.number }}-amd64 + + - name: Install Docker Scout + run: | + curl -fsSL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh -o install-scout.sh + sh install-scout.sh + + - name: Docker Scout Compare (amd64) + run: | + docker scout compare ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:pr-${{ github.event.pull_request.number }}-amd64 --to ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:latest --ignore-unchanged --only-severity critical,high diff --git a/.gitea/workflows/update-check.yaml b/.gitea/workflows/update-check.yaml new file mode 100644 index 0000000..fadfd7e --- /dev/null +++ b/.gitea/workflows/update-check.yaml @@ -0,0 +1,49 @@ +name: Check for Flutter SDK Updates + +on: + schedule: + - cron: '0 8 * * *' + workflow_dispatch: + +jobs: + check-update: + runs-on: ubuntu-latest + steps: + - name: Get latest Flutter stable version + id: flutter + run: | + LATEST=$(curl -fsSL https://storage.googleapis.com/flutter_infra_release/releases/releases_linux.json \ + | jq -r '.current_release.stable as $hash | .releases[] | select(.hash == $hash) | .version') + echo "version=${LATEST}" >> $GITHUB_OUTPUT + echo "Latest Flutter stable: ${LATEST}" + + - name: Check if release already exists + id: existing + run: | + VERSION="${{ steps.flutter.outputs.version }}" + STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ + "${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases/tags/${VERSION}") + if [ "$STATUS" = "200" ]; then + echo "exists=true" >> $GITHUB_OUTPUT + echo "Release ${VERSION} already exists, skipping" + else + echo "exists=false" >> $GITHUB_OUTPUT + echo "Release ${VERSION} not found, will create" + fi + + - name: Create release for new version + if: steps.existing.outputs.exists == 'false' && steps.flutter.outputs.version != '' + run: | + VERSION="${{ steps.flutter.outputs.version }}" + echo "Creating release for Flutter ${VERSION}" + curl -fsSL -X POST \ + -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ + -H "Content-Type: application/json" \ + "${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases" \ + -d "{ + \"tag_name\": \"${VERSION}\", + \"name\": \"Flutter SDK ${VERSION}\", + \"body\": \"Automated release for Flutter stable ${VERSION}\", + \"draft\": false, + \"prerelease\": false + }" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8894a38 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,51 @@ +FROM debian:bookworm-slim + +ARG FLUTTER_VERSION=3.38.9 + +LABEL org.opencontainers.image.title="gpb-flutter-sdk-web" +LABEL org.opencontainers.image.description="Minimal Flutter SDK for Web/WASM CI builds" +LABEL org.opencontainers.image.version="${FLUTTER_VERSION}" + +# Install minimal dependencies for Flutter web builds +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + git \ + unzip \ + xz-utils \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +ENV FLUTTER_HOME=/opt/flutter +ENV PATH="${FLUTTER_HOME}/bin:${FLUTTER_HOME}/bin/cache/dart-sdk/bin:${PATH}" + +# Download Flutter SDK from official archive +RUN curl -fsSL "https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz" \ + -o /tmp/flutter.tar.xz && \ + tar xf /tmp/flutter.tar.xz -C /opt && \ + rm /tmp/flutter.tar.xz + +# Mark git directory as safe (tarball is owned by different uid) +RUN git config --global --add safe.directory "${FLUTTER_HOME}" + +# Configure for web-only (disable everything else) +RUN flutter config --enable-web \ + --no-enable-android \ + --no-enable-ios \ + --no-enable-linux-desktop \ + --no-enable-macos-desktop \ + --no-enable-windows-desktop + +# Precache only web artifacts +RUN flutter precache --web \ + --no-android \ + --no-ios \ + --no-linux \ + --no-macos \ + --no-windows \ + --no-fuchsia \ + --no-universal + +# Verify installation +RUN flutter doctor -v + +WORKDIR /app