Skip to content

update build.yml

update build.yml #13

Workflow file for this run

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