name: 🚀✨

on:
  workflow_dispatch:
    inputs:
      build_mode:
        description: 'Build mode'
        required: true
        default: 'rebuild'
        type: choice
        options:
          - rebuild
          - version_bump
      variants:
        description: 'Which variants to build'
        required: true
        default: 'both'
        type: choice
        options:
          - both
          - latest
          - edge
      release_type:
        description: 'Release type (only for version_bump mode)'
        required: false
        default: 'patch'
        type: choice
        options:
          - major
          - minor
          - patch
  schedule:
    - cron: '30 18 * * 0'
    - cron: '0 12 */3 * *'
  push:
    tags:
      - 'v*.*.*'

permissions:
  contents: read

env:
  GHCR_REGISTRY: ghcr.io
  GHCR_IMAGE_NAME: ${{ github.repository_owner }}/onion-relay
  DOCKERHUB_IMAGE_NAME: r3bo0tbx1/onion-relay

jobs:
  determine-version:
    name: 🏷️ Determine Version and Build Type
    runs-on: ubuntu-latest
    permissions:
      contents: read
    outputs:
      version: ${{ steps.version.outputs.version }}
      build_type: ${{ steps.version.outputs.build_type }}
      is_release: ${{ steps.version.outputs.is_release }}
      build_date: ${{ steps.version.outputs.build_date }}
      short_sha: ${{ steps.version.outputs.short_sha }}
      build_variants: ${{ steps.version.outputs.build_variants }}

    steps:
      - name: 📥 Checkout Repository
        uses: actions/checkout@v5
        with:
          fetch-depth: 0

      - name: 🔍 Detect Version and Build Type
        id: version
        run: |
          set -e
          echo "🔍 Determining version context..."
          BUILD_VARIANTS="both"

          if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
            VERSION="${GITHUB_REF#refs/tags/v}"
            BUILD_TYPE="release"
            IS_RELEASE="true"
            BUILD_VARIANTS="both"
            echo "🏷️ Release tag detected: v${VERSION}"
          elif [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
            BUILD_MODE="${{ github.event.inputs.build_mode }}"
            BUILD_VARIANTS="${{ github.event.inputs.variants }}"
            LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v1.0.0")

            if [[ "${BUILD_MODE}" == "rebuild" ]]; then
              VERSION="${LATEST_TAG#v}"
              BUILD_TYPE="manual-rebuild"
              IS_RELEASE="false"
              echo "🔄 Manual rebuild of last release: ${VERSION} (with updated packages)"
              echo "   Variants: ${BUILD_VARIANTS}"
            else
              VERSION="${LATEST_TAG#v}-manual-${GITHUB_RUN_NUMBER}"
              BUILD_TYPE="manual"
              IS_RELEASE="false"
              echo "👤 Manual build version: ${VERSION}"
              echo "   Variants: ${BUILD_VARIANTS}"
            fi
          elif [[ "${GITHUB_EVENT_NAME}" == "schedule" ]]; then
            LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v1.0.0")
            VERSION="${LATEST_TAG#v}"
            IS_RELEASE="false"

            CURRENT_HOUR=$(date -u +%H)
            if [[ "${CURRENT_HOUR}" == "18" ]]; then
              BUILD_TYPE="weekly"
              BUILD_VARIANTS="latest"
              echo "📅 Weekly rebuild of last release: ${VERSION} (stable variant with updated packages)"
            else
              BUILD_TYPE="edge-rebuild"
              BUILD_VARIANTS="edge"
              echo "⚡ Edge-only rebuild of last release: ${VERSION} (edge variant with updated packages)"
            fi
          else
            LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v1.0.0")
            VERSION="${LATEST_TAG#v}"
            BUILD_TYPE="unknown"
            IS_RELEASE="false"
            BUILD_VARIANTS="both"
            echo "⚠️ Unknown trigger: ${VERSION}"
          fi
          BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
          SHORT_SHA=$(git rev-parse --short HEAD)
          echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
          echo "build_type=${BUILD_TYPE}" >> "$GITHUB_OUTPUT"
          echo "is_release=${IS_RELEASE}" >> "$GITHUB_OUTPUT"
          echo "build_date=${BUILD_DATE}" >> "$GITHUB_OUTPUT"
          echo "short_sha=${SHORT_SHA}" >> "$GITHUB_OUTPUT"
          echo "build_variants=${BUILD_VARIANTS}" >> "$GITHUB_OUTPUT"

      - name: 📋 Version Information
        run: |
          echo "📦 Build Info:"
          echo "  🏷️ Version: ${{ steps.version.outputs.version }}"
          echo "  📝 Build Type: ${{ steps.version.outputs.build_type }}"
          echo "  ✅ Release: ${{ steps.version.outputs.is_release }}"
          echo "  📅 Date: ${{ steps.version.outputs.build_date }}"
          echo "  🔑 SHA: ${{ steps.version.outputs.short_sha }}"

  build-and-push:
    name: 🏗️ Multi-Arch Build and Push (${{ matrix.variant.name }})
    runs-on: ubuntu-latest
    needs: determine-version
    permissions:
      contents: read
      packages: write
    if: |
      github.event_name != 'workflow_run' ||
      github.event.workflow_run.conclusion == 'success'
    strategy:
      fail-fast: false
      matrix:
        variant:
          - name: stable
            dockerfile: Dockerfile
            suffix: ""
            is_latest: "true"
            base: "Alpine 3.23.3"
            push_dockerhub: "true"
          - name: edge
            dockerfile: Dockerfile.edge
            suffix: "-edge"
            is_latest: "false"
            base: "Alpine edge"
            push_dockerhub: "true"

    steps:
      - name: 📥 Checkout Repository
        uses: actions/checkout@v5

      - name: 🎯 Check if variant should be built
        id: should_build
        run: |
          BUILD_VARIANTS="${{ needs.determine-version.outputs.build_variants }}"
          VARIANT_NAME="${{ matrix.variant.name }}"

          SHOULD_BUILD="false"

          if [ "$BUILD_VARIANTS" = "both" ]; then
            SHOULD_BUILD="true"
          elif [ "$BUILD_VARIANTS" = "latest" ] && [ "$VARIANT_NAME" = "stable" ]; then
            SHOULD_BUILD="true"
          elif [ "$BUILD_VARIANTS" = "edge" ] && [ "$VARIANT_NAME" = "edge" ]; then
            SHOULD_BUILD="true"
          fi

          echo "should_build=${SHOULD_BUILD}" >> "$GITHUB_OUTPUT"
          echo "🔍 Variant: ${VARIANT_NAME}, Build Variants: ${BUILD_VARIANTS}, Should Build: ${SHOULD_BUILD}"

      - name: 🎯 Verify Tools Directory
        if: steps.should_build.outputs.should_build == 'true'
        run: |
          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          echo "📝 Pre-Build: Verifying Tools"
          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          echo ""

          if [ ! -d "tools" ]; then
            echo "❌ tools/ directory not found"
            exit 1
          fi

          TOOL_COUNT=0

          for file in tools/*; do
            [ -f "$file" ] || continue
            filename=$(basename "$file")

            if head -1 "$file" 2>/dev/null | grep -q "^#!/bin/sh"; then
              echo "✅ $filename (busybox sh)"
              TOOL_COUNT=$((TOOL_COUNT + 1))
            fi
          done

          echo ""
          if [ $TOOL_COUNT -lt 1 ]; then
            echo "❌ Build blocked: No tools found in tools/"
            exit 1
          else
            echo "🎉 Found $TOOL_COUNT diagnostic tools (busybox-only, no .sh extension)"
          fi

      - name: 🔧 Normalize scripts before build
        if: steps.should_build.outputs.should_build == 'true'
        run: |
          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          echo "🔧 Normalizing Line Endings and Permissions"
          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          echo ""

          sudo apt-get update -qq && sudo apt-get install -y dos2unix

          echo "📄 Processing main scripts..."
          for script in docker-entrypoint.sh healthcheck.sh Dockerfile Dockerfile.edge; do
            if [ -f "$script" ]; then
              dos2unix "$script" 2>/dev/null || true
              echo "   ✅ Normalized: $script"
            fi
          done

          echo ""
          echo "📁 Processing tools/*..."
          if [ -d "tools" ]; then
            find tools -type f -exec dos2unix {} \; 2>/dev/null || true
            TOOL_COUNT=$(find tools -type f | wc -l)
            echo "   ✅ Normalized: $TOOL_COUNT tool scripts"
          fi

          echo ""
          echo "🔐 Setting execute permissions..."
          chmod +x docker-entrypoint.sh healthcheck.sh 2>/dev/null || true
          [ -d "tools" ] && chmod +x tools/* 2>/dev/null || true

          echo "   ✅ Permissions verified"
          echo ""
          echo "🎉 Normalization complete"

      - name: 🐳 Login to Docker Hub
        if: steps.should_build.outputs.should_build == 'true' && matrix.variant.push_dockerhub == 'true'
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: 📦 Login to GitHub Container Registry
        if: steps.should_build.outputs.should_build == 'true'
        uses: docker/login-action@v3
        with:
          registry: ${{ env.GHCR_REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: 🖥️ Set up QEMU
        if: steps.should_build.outputs.should_build == 'true'
        uses: docker/setup-qemu-action@v3
        with:
          platforms: arm64,amd64

      - name: 🔨 Set up Docker Buildx
        if: steps.should_build.outputs.should_build == 'true'
        uses: docker/setup-buildx-action@v3

      - name: 🏷️ Generate Docker Tags
        if: steps.should_build.outputs.should_build == 'true'
        id: tags
        run: |
          VERSION="${{ needs.determine-version.outputs.version }}"
          BUILD_TYPE="${{ needs.determine-version.outputs.build_type }}"
          VARIANT_NAME="${{ matrix.variant.name }}"
          SUFFIX="${{ matrix.variant.suffix }}"
          IS_LATEST="${{ matrix.variant.is_latest }}"
          PUSH_DOCKERHUB="${{ matrix.variant.push_dockerhub }}"

          echo "🏷️ Generating tags for variant: ${VARIANT_NAME}"
          echo "   Version: ${VERSION}${SUFFIX}"
          echo "   Build Type: ${BUILD_TYPE}"
          echo "   Is Latest: ${IS_LATEST}"
          echo "   Push to Docker Hub: ${PUSH_DOCKERHUB}"
          echo ""

          TAGS=()

          TAGS+=("${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${VERSION}${SUFFIX}")

          if [ "$BUILD_TYPE" = "release" ]; then
            if [ "$IS_LATEST" = "true" ]; then
              TAGS+=("${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:latest")
            else
              TAGS+=("${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:edge")
            fi

            if [ "$PUSH_DOCKERHUB" = "true" ]; then
              if [ "$IS_LATEST" = "true" ]; then
                TAGS+=("${{ env.DOCKERHUB_IMAGE_NAME }}:${VERSION}")
                TAGS+=("${{ env.DOCKERHUB_IMAGE_NAME }}:latest")
              else
                TAGS+=("${{ env.DOCKERHUB_IMAGE_NAME }}:edge")
              fi
            fi
          elif [ "$BUILD_TYPE" = "weekly" ] || [ "$BUILD_TYPE" = "manual-rebuild" ] || [ "$BUILD_TYPE" = "edge-rebuild" ]; then
            if [ "$IS_LATEST" = "true" ]; then
              TAGS+=("${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:latest")
            else
              TAGS+=("${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:edge")
            fi

            if [ "$PUSH_DOCKERHUB" = "true" ]; then
              if [ "$IS_LATEST" = "true" ]; then
                TAGS+=("${{ env.DOCKERHUB_IMAGE_NAME }}:${VERSION}")
                TAGS+=("${{ env.DOCKERHUB_IMAGE_NAME }}:latest")
              else
                TAGS+=("${{ env.DOCKERHUB_IMAGE_NAME }}:edge")
              fi
            fi
          else
            if [ "$PUSH_DOCKERHUB" = "true" ]; then
              if [ "$IS_LATEST" = "true" ]; then
                TAGS+=("${{ env.DOCKERHUB_IMAGE_NAME }}:${VERSION}")
              else
                TAGS+=("${{ env.DOCKERHUB_IMAGE_NAME }}:edge")
              fi
            fi
          fi

          TAGS_STR=$(IFS=','; echo "${TAGS[*]}")
          echo "tags=${TAGS_STR}" >> "$GITHUB_OUTPUT"

          echo "📋 Generated tags:"
          for tag in "${TAGS[@]}"; do
            echo "   - ${tag}"
          done

      - name: 🚀 Build and Push Multi-Arch Image
        if: steps.should_build.outputs.should_build == 'true'
        uses: docker/build-push-action@v6
        with:
          context: .
          file: ./${{ matrix.variant.dockerfile }}
          platforms: linux/amd64,linux/arm64
          push: true
          tags: ${{ steps.tags.outputs.tags }}
          build-args: |
            BUILD_DATE=${{ needs.determine-version.outputs.build_date }}
            BUILD_VERSION=${{ needs.determine-version.outputs.version }}
          cache-from: type=gha,scope=${{ matrix.variant.name }}
          cache-to: type=gha,mode=max,scope=${{ matrix.variant.name }}
          labels: |
            org.opencontainers.image.title=Tor Guard Relay (${{ matrix.variant.name }})
            org.opencontainers.image.description=Hardened Tor Guard Relay (${{ matrix.variant.base }})
            org.opencontainers.image.version=${{ needs.determine-version.outputs.version }}${{ matrix.variant.suffix }}
            org.opencontainers.image.created=${{ needs.determine-version.outputs.build_date }}
            org.opencontainers.image.revision=${{ github.sha }}
            org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
          sbom: true
          provenance: true

      - name: 📋 Generate SBOM (CycloneDX & SPDX)
        if: steps.should_build.outputs.should_build == 'true' && needs.determine-version.outputs.is_release == 'true'
        run: |
          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          echo "📋 Generating Software Bill of Materials (SBOM)"
          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          echo ""

          curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin

          VERSION="${{ needs.determine-version.outputs.version }}"
          SUFFIX="${{ matrix.variant.suffix }}"
          VARIANT="${{ matrix.variant.name }}"
          IMAGE="${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${VERSION}${SUFFIX}"

          echo "📦 Generating SBOM for ${VARIANT} variant"
          echo "   Image: ${IMAGE}"
          echo ""

          echo "📄 Generating CycloneDX JSON format..."
          syft "${IMAGE}" -o cyclonedx-json > "sbom-${VARIANT}-cyclonedx-v${VERSION}.json"
          echo "   ✅ sbom-${VARIANT}-cyclonedx-v${VERSION}.json"

          echo "📄 Generating CycloneDX XML format..."
          syft "${IMAGE}" -o cyclonedx-xml > "sbom-${VARIANT}-cyclonedx-v${VERSION}.xml"
          echo "   ✅ sbom-${VARIANT}-cyclonedx-v${VERSION}.xml"

          echo "📄 Generating SPDX JSON format..."
          syft "${IMAGE}" -o spdx-json > "sbom-${VARIANT}-spdx-v${VERSION}.json"
          echo "   ✅ sbom-${VARIANT}-spdx-v${VERSION}.json"

          echo "📄 Generating SPDX tag-value format..."
          syft "${IMAGE}" -o spdx-tag-value > "sbom-${VARIANT}-spdx-v${VERSION}.spdx"
          echo "   ✅ sbom-${VARIANT}-spdx-v${VERSION}.spdx"

          echo "📄 Generating human-readable table..."
          syft "${IMAGE}" -o table > "sbom-${VARIANT}-table-v${VERSION}.txt"
          echo "   ✅ sbom-${VARIANT}-table-v${VERSION}.txt"

          echo ""
          echo "✅ SBOM generation complete for ${VARIANT} variant"
          echo ""
          echo "📊 Package Statistics:"
          jq '.components | length' "sbom-${VARIANT}-cyclonedx-v${VERSION}.json" | xargs echo "   Total packages:"

      - name: 📤 Upload SBOM Artifacts
        if: steps.should_build.outputs.should_build == 'true' && needs.determine-version.outputs.is_release == 'true'
        uses: actions/upload-artifact@v4
        with:
          name: sbom-${{ matrix.variant.name }}-v${{ needs.determine-version.outputs.version }}
          path: |
            sbom-${{ matrix.variant.name }}-*.json
            sbom-${{ matrix.variant.name }}-*.xml
            sbom-${{ matrix.variant.name }}-*.spdx
            sbom-${{ matrix.variant.name }}-*.txt
          retention-days: 7

  release-notes:
    name: 📝 Generate Release Notes
    runs-on: ubuntu-latest
    needs: [determine-version, build-and-push]
    permissions:
      contents: write
    if: needs.determine-version.outputs.is_release == 'true'

    steps:
      - name: 📥 Checkout Repository
        uses: actions/checkout@v5
        with:
          fetch-depth: 0

      - name: 📝 Generate Notes
        run: |
          VERSION="${{ needs.determine-version.outputs.version }}"
          GHCR_IMAGE="${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}"
          DOCKERHUB_IMAGE="${{ env.DOCKERHUB_IMAGE_NAME }}"

          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          echo "📝 Generating Release Notes for v${VERSION}"
          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          echo ""

          CHANGELOG_FOUND=0

          if [ -f CHANGELOG.md ]; then
            echo "🔍 Checking CHANGELOG.md for v${VERSION}..."

            awk -v version="${VERSION}" '
              $0 ~ "^##[[:space:]]*(\\[v?" version "\\]|v" version ")([[:space:]]*-.*)?$" {p=1; next}
              p && /^##[[:space:]]*\[/ && !($0 ~ version) {p=0}
              p
            ' CHANGELOG.md > tmp_notes.txt

            if [ -s tmp_notes.txt ]; then
              # Strip trailing blank lines and --- separators from changelog extract
              while [ -s tmp_notes.txt ]; do
                LAST_LINE=$(tail -1 tmp_notes.txt)
                case "$(printf '%s' "$LAST_LINE" | tr -d '[:space:]')" in
                  ""|"---") sed -i '$ d' tmp_notes.txt ;;
                  *) break ;;
                esac
              done

              echo "✅ Found changelog section for v${VERSION} in CHANGELOG.md"
              CHANGELOG_FOUND=1

              cat tmp_notes.txt > release_notes.md
            else
              echo "⚠️ No changelog section found for v${VERSION} in CHANGELOG.md"
            fi
          else
            echo "⚠️ CHANGELOG.md not found"
          fi

          if [ "$CHANGELOG_FOUND" = "0" ]; then
            echo "📋 Auto-generating release notes from commits..."

            if [ -x scripts/release/generate-release-notes.sh ]; then
              chmod +x scripts/release/generate-release-notes.sh
              ./scripts/release/generate-release-notes.sh --format github "${VERSION}" > tmp_auto_notes.md
              # Strip title (release 'name' already shows it) and footer (workflow appends its own)
              sed '/^## 🧅/d; /^\*\*Full Changelog\*\*/d' tmp_auto_notes.md > release_notes.md
              # Remove trailing --- and blank lines left by the script footer
              while [ -s release_notes.md ]; do
                LAST_LINE=$(tail -1 release_notes.md)
                case "$(printf '%s' "$LAST_LINE" | tr -d '[:space:]')" in
                  ""|"---") sed -i '$ d' release_notes.md ;;
                  *) break ;;
                esac
              done
              echo "✅ Auto-generated release notes from conventional commits"
            else
              echo "### Changes" > release_notes.md
              echo "" >> release_notes.md
              PREV_TAG=$(git tag --sort=-v:refname | grep -v "^v${VERSION}$" | head -1)
              [ -z "$PREV_TAG" ] && PREV_TAG=$(git rev-list --max-parents=0 HEAD)
              git log --pretty=format:"- %s (\`%h\`) by %an" "${PREV_TAG}..HEAD" >> release_notes.md || echo "- Initial release" >> release_notes.md
              echo "" >> release_notes.md
              echo "⚠️ **Note:** Release notes were auto-generated from commit history." >> release_notes.md
              echo "For detailed changes, see the commit history below." >> release_notes.md
              echo "✅ Generated basic release notes from commit history"
            fi
          fi

          echo "" >> release_notes.md
          echo "---" >> release_notes.md
          ALPINE_VERSION=$(grep -oP '^FROM alpine:\K[0-9.]+' Dockerfile 2>/dev/null || echo "latest")

          echo "" >> release_notes.md
          echo "### 🐳 Docker Images" >> release_notes.md
          echo "" >> release_notes.md
          echo "**Stable Variant (Recommended for Production)**" >> release_notes.md
          echo "" >> release_notes.md
          echo "- Base: Alpine ${ALPINE_VERSION}" >> release_notes.md
          echo "- Proven stability with weekly security updates" >> release_notes.md
          echo "" >> release_notes.md
          echo "\`\`\`bash" >> release_notes.md
          echo "# From GitHub Container Registry (GHCR)" >> release_notes.md
          echo "docker pull ${GHCR_IMAGE}:${VERSION}" >> release_notes.md
          echo "docker pull ${GHCR_IMAGE}:latest" >> release_notes.md
          echo "" >> release_notes.md
          echo "# From Docker Hub" >> release_notes.md
          echo "docker pull ${DOCKERHUB_IMAGE}:${VERSION}" >> release_notes.md
          echo "docker pull ${DOCKERHUB_IMAGE}:latest" >> release_notes.md
          echo "\`\`\`" >> release_notes.md
          echo "" >> release_notes.md
          echo "**Edge Variant (Testing Only)**" >> release_notes.md
          echo "" >> release_notes.md
          echo "- Base: Alpine edge (bleeding edge)" >> release_notes.md
          echo "- ⚠️ **NOT recommended for production** - faster updates, less stable" >> release_notes.md
          echo "" >> release_notes.md
          echo "\`\`\`bash" >> release_notes.md
          echo "# From GitHub Container Registry (GHCR) - versioned + simple tags" >> release_notes.md
          echo "docker pull ${GHCR_IMAGE}:${VERSION}-edge" >> release_notes.md
          echo "docker pull ${GHCR_IMAGE}:edge" >> release_notes.md
          echo "" >> release_notes.md
          echo "# From Docker Hub - simple tag only" >> release_notes.md
          echo "docker pull ${DOCKERHUB_IMAGE}:edge" >> release_notes.md
          echo "\`\`\`" >> release_notes.md
          echo "" >> release_notes.md
          echo "### 📋 Software Bill of Materials (SBOM)" >> release_notes.md
          echo "" >> release_notes.md
          echo "This release includes comprehensive SBOM files for **both variants** for supply chain security:" >> release_notes.md
          echo "" >> release_notes.md
          echo "- **CycloneDX**: JSON and XML formats (stable + edge)" >> release_notes.md
          echo "- **SPDX**: JSON and tag-value formats (stable + edge)" >> release_notes.md
          echo "- **Human-readable**: Table format (stable + edge)" >> release_notes.md
          echo "" >> release_notes.md
          echo "Download SBOM files from the release assets below (prefixed with \`stable-\` or \`edge-\`)." >> release_notes.md
          echo "" >> release_notes.md
          echo "---" >> release_notes.md
          echo "" >> release_notes.md
          PREV_TAG=$(git tag --sort=-v:refname | grep -v "^v${VERSION}$" | head -1)
          [ -z "$PREV_TAG" ] && PREV_TAG="v1.0.0"
          echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREV_TAG}...v${VERSION}" >> release_notes.md

          echo ""
          echo "✅ Release notes generation complete"

      - name: 📦 Download SBOM Artifacts (Stable)
        uses: actions/download-artifact@v4
        with:
          name: sbom-stable-v${{ needs.determine-version.outputs.version }}
          path: ./sbom

      - name: 📦 Download SBOM Artifacts (Edge)
        uses: actions/download-artifact@v4
        with:
          name: sbom-edge-v${{ needs.determine-version.outputs.version }}
          path: ./sbom

      - name: 🏷️ Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: v${{ needs.determine-version.outputs.version }}
          name: "🧅 Tor Guard Relay v${{ needs.determine-version.outputs.version }}"
          body_path: release_notes.md
          files: |
            sbom/*.json
            sbom/*.xml
            sbom/*.spdx
            sbom/*.txt
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
