update build.yml #13
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 Images with Nix Flakes | |
| on: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| branches: [ main ] | |
| schedule: | |
| - cron: '0 2 * * 1' # Weekly on Monday at 2 AM | |
| workflow_dispatch: | |
| inputs: | |
| push_images: | |
| description: 'Push images to registry' | |
| type: boolean | |
| default: true | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| attestations: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Install Nix 2.31.1 | |
| run: | | |
| # 安装最新稳定版 Nix 2.31.1 (单用户模式) | |
| sh <(curl -L https://nixos.org/nix/install) --no-daemon --yes | |
| # 重新加载环境 | |
| . /home/runner/.nix-profile/etc/profile.d/nix.sh | |
| # 验证安装 | |
| nix --version | |
| - name: Configure Nix | |
| run: | | |
| # 加载 Nix 环境 | |
| . /home/runner/.nix-profile/etc/profile.d/nix.sh | |
| # 配置 Nix 以支持 Flakes | |
| mkdir -p ~/.config/nix | |
| cat > ~/.config/nix/nix.conf << EOF | |
| experimental-features = nix-command flakes | |
| allow-import-from-derivation = true | |
| EOF | |
| # 验证配置 | |
| nix --version | |
| - name: Build Docker image with Nix Flakes | |
| run: | | |
| # 加载 Nix 环境 | |
| . /home/runner/.nix-profile/etc/profile.d/nix.sh | |
| # 使用 nix flake 构建,利用 flake.nix 中定义的环境 | |
| # 启用缓存以提高构建速度 | |
| nix build .#docker-image --option sandbox false | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to Container Registry | |
| if: github.event.inputs.push_images != 'false' | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Load Docker image | |
| run: | | |
| # 使用 nix build 的结果加载 Docker 镜像 | |
| docker load < result | |
| - name: Extract metadata | |
| id: meta | |
| if: github.event.inputs.push_images != 'false' | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=raw,value=secure-latest | |
| - name: Tag Docker image | |
| if: github.event.inputs.push_images != 'false' | |
| run: | | |
| # Get the image ID from the loaded image | |
| IMAGE_ID=$(docker images --format "{{.ID}}" | head -1) | |
| echo "Image ID: $IMAGE_ID" | |
| # Tag with all metadata tags | |
| for tag in ${{ steps.meta.outputs.tags }}; do | |
| echo "Tagging with: $tag" | |
| docker tag $IMAGE_ID $tag | |
| done | |
| - name: Push Docker image | |
| if: github.event.inputs.push_images != 'false' | |
| run: | | |
| for tag in ${{ steps.meta.outputs.tags }}; do | |
| echo "Pushing: $tag" | |
| docker push $tag | |
| done | |
| - name: Run security scan | |
| if: github.event.inputs.push_images != 'false' | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:secure-latest | |
| format: 'sarif' | |
| output: 'trivy-results.sarif' | |
| - name: Upload Trivy scan results | |
| if: github.event.inputs.push_images != 'false' | |
| uses: github/codeql-action/upload-sarif@v2 | |
| with: | |
| sarif_file: 'trivy-results.sarif' | |
| test: | |
| runs-on: ubuntu-latest | |
| needs: build | |
| if: github.event.inputs.push_images != 'false' | |
| steps: | |
| - name: Test Python version | |
| run: | | |
| docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:secure-latest python --version | |
| - name: Test UV installation | |
| run: | | |
| docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:secure-latest uv --version | |
| - name: Test security restrictions | |
| run: | | |
| # Test that dangerous modules are restricted | |
| docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:secure-latest python -c " | |
| try: | |
| import os | |
| print('ERROR: os module should be restricted') | |
| exit(1) | |
| except ImportError: | |
| print('OK: os module is properly restricted') | |
| " | |
| - name: Test Gurobi availability | |
| run: | | |
| # Test that Gurobi is available (without license) | |
| docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:secure-latest python -c " | |
| try: | |
| import gurobipy | |
| print('OK: Gurobi Python package is available') | |
| except ImportError as e: | |
| print(f'ERROR: Gurobi not available: {e}') | |
| exit(1) | |
| " | |
| - name: Test scientific packages | |
| run: | | |
| # Test that scientific packages are available | |
| docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:secure-latest python -c " | |
| import numpy | |
| import scipy | |
| import pandas | |
| import matplotlib | |
| import sklearn | |
| print('OK: All scientific packages are available') | |
| print(f'NumPy version: {numpy.__version__}') | |
| print(f'SciPy version: {scipy.__version__}') | |
| print(f'Pandas version: {pandas.__version__}') | |
| " | |
| cleanup: | |
| runs-on: ubuntu-latest | |
| needs: [build, test] | |
| if: always() && github.event.inputs.push_images != 'false' | |
| permissions: | |
| packages: write | |
| steps: | |
| - name: Clean up old images | |
| uses: dataaxiom/ghcr-cleanup-action@v1 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| package-name: ${{ env.IMAGE_NAME }} | |
| keep-versions: 10 | |
| generate-summary: | |
| runs-on: ubuntu-latest | |
| needs: [build, test] | |
| if: always() | |
| steps: | |
| - name: Generate summary | |
| run: | | |
| echo "## 🐳 Docker Image Build Summary (Nix Flakes)" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Image:** \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Tags:**" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`secure-latest\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Build System:**" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ Nix Flakes for reproducible builds" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ Declarative environment management" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Features:**" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ Secure Python 3.12 environment" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ UV package manager" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ Gurobi optimization solver" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ Scientific computing packages" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ Non-root user execution" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ Resource limits and security restrictions" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Registry:** [GitHub Container Registry](https://github.com/orgs/reaslab/packages)" >> $GITHUB_STEP_SUMMARY |