Build and Push Docker Image #9
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 | |
| on: | |
| push: | |
| branches: [main] | |
| tags: ['v*'] | |
| pull_request: | |
| branches: [main] | |
| schedule: | |
| # Check for Headscale updates weekly (Sunday at 00:00 UTC) | |
| - cron: '0 0 * * 0' | |
| workflow_dispatch: | |
| inputs: | |
| tailscale_version: | |
| description: 'Override Tailscale version (e.g., v1.76.1). Leave empty to auto-detect from Headscale.' | |
| required: false | |
| type: string | |
| env: | |
| REGISTRY: ghcr.io | |
| # Go version must match the requirement in Tailscale's go.mod | |
| GO_VERSION: '1.25' | |
| jobs: | |
| # First job: Detect the Tailscale version used by Headscale | |
| detect-version: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| tailscale_version: ${{ steps.get-version.outputs.version }} | |
| version_changed: ${{ steps.check-change.outputs.changed }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Get Tailscale version from Headscale | |
| id: get-version | |
| run: | | |
| # If manual override is provided, use it | |
| if [ -n "${{ github.event.inputs.tailscale_version }}" ]; then | |
| VERSION="${{ github.event.inputs.tailscale_version }}" | |
| echo "Using manually specified version: $VERSION" | |
| else | |
| # Fetch Headscale's go.mod and extract tailscale version | |
| echo "Fetching Tailscale version from Headscale go.mod..." | |
| GO_MOD_URL="https://raw.githubusercontent.com/juanfont/headscale/main/go.mod" | |
| # Extract version like "v1.76.1" from "tailscale.com v1.76.1" | |
| VERSION=$(curl -sL "$GO_MOD_URL" | grep -E "^\s*tailscale\.com\s+v" | head -1 | awk '{print $2}') | |
| if [ -z "$VERSION" ]; then | |
| echo "Failed to detect Tailscale version from Headscale, using fallback" | |
| VERSION="v1.76.1" | |
| fi | |
| echo "Detected Tailscale version from Headscale: $VERSION" | |
| fi | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "TAILSCALE_VERSION=$VERSION" >> $GITHUB_ENV | |
| - name: Check if version changed | |
| id: check-change | |
| run: | | |
| # Read the last built version from cache or file | |
| CURRENT_VERSION="${{ steps.get-version.outputs.version }}" | |
| CACHE_FILE=".last-tailscale-version" | |
| if [ -f "$CACHE_FILE" ]; then | |
| LAST_VERSION=$(cat "$CACHE_FILE") | |
| if [ "$CURRENT_VERSION" != "$LAST_VERSION" ]; then | |
| echo "Version changed: $LAST_VERSION -> $CURRENT_VERSION" | |
| echo "changed=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "Version unchanged: $CURRENT_VERSION" | |
| echo "changed=false" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| echo "No previous version found, treating as new" | |
| echo "changed=true" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Display version info | |
| run: | | |
| echo "## Tailscale Version Detection" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY | |
| echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Detected Version | \`${{ steps.get-version.outputs.version }}\` |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Source | Headscale go.mod |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Go Version | \`${{ env.GO_VERSION }}\` |" >> $GITHUB_STEP_SUMMARY | |
| # Second job: Build and push the Docker image | |
| build: | |
| needs: detect-version | |
| # Always build on push/PR, only build on schedule if version changed | |
| if: github.event_name != 'schedule' || needs.detect-version.outputs.version_changed == 'true' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| attestations: write | |
| id-token: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Set image name to lowercase | |
| id: image | |
| run: | | |
| echo "name=${GITHUB_REPOSITORY,,}" >> $GITHUB_OUTPUT | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to Container Registry | |
| if: github.event_name != 'pull_request' | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ steps.image.outputs.name }} | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=pr | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=semver,pattern={{major}} | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| type=raw,value=tailscale-${{ needs.detect-version.outputs.tailscale_version }},enable={{is_default_branch}} | |
| - name: Build and push Docker image | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| platforms: linux/amd64,linux/arm64 | |
| push: ${{ github.event_name != 'pull_request' }} | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| # Disable provenance to avoid attestation push issues | |
| provenance: false | |
| sbom: false | |
| build-args: | | |
| GO_VERSION=${{ env.GO_VERSION }} | |
| TAILSCALE_VERSION=${{ needs.detect-version.outputs.tailscale_version }} | |
| - name: Run Trivy vulnerability scanner | |
| if: github.event_name != 'pull_request' | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: ${{ env.REGISTRY }}/${{ steps.image.outputs.name }}:latest | |
| format: 'sarif' | |
| output: 'trivy-results.sarif' | |
| severity: 'CRITICAL,HIGH' | |
| continue-on-error: true | |
| - name: Build summary | |
| if: github.event_name != 'pull_request' | |
| run: | | |
| echo "## Build Complete!" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Image Details" >> $GITHUB_STEP_SUMMARY | |
| echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY | |
| echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Tailscale Version | \`${{ needs.detect-version.outputs.tailscale_version }}\` |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Go Version | \`${{ env.GO_VERSION }}\` |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Platforms | \`linux/amd64, linux/arm64\` |" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Pull Command" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY | |
| echo "docker pull ${{ env.REGISTRY }}/${{ steps.image.outputs.name }}:latest" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY |