diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 49e5bcd..754b7b7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,579 +1,368 @@ -name: ๐Ÿงฑโœ… Build and Validation +name: ๐Ÿš€โœจ Release and Weekly Builds on: workflow_dispatch: - pull_request: - branches: - - main - - develop + inputs: + release_type: + description: 'Release type' + required: true + default: 'patch' + type: choice + options: + - major + - minor + - patch + schedule: + - cron: '0 3 * * 1' push: + tags: + - 'v*.*.*' + workflow_run: + workflows: ["๐Ÿงฑโœ… Build and Validation"] + types: + - completed branches: - main - develop - paths: - - 'Dockerfile' - - 'docker-entrypoint.sh' - - 'tools/**' - - '.github/workflows/release.yml' - - '.github/workflows/validate.yml' permissions: - contents: read + contents: write + packages: write + +env: + GHCR_REGISTRY: ghcr.io + GHCR_IMAGE_NAME: ${{ github.repository_owner }}/onion-relay + DOCKERHUB_IMAGE_NAME: r3bo0tbx1/onion-relay jobs: - lint: - name: ๐Ÿ” Lint and Validate + determine-version: + name: ๐Ÿท๏ธ Determine Version and Build Type runs-on: ubuntu-latest + 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 }} steps: - - name: Checkout Repository + - 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..." + if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then + VERSION="${GITHUB_REF#refs/tags/v}" + BUILD_TYPE="release" + IS_RELEASE="true" + echo "๐Ÿท๏ธ Release tag detected: v${VERSION}" + elif [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v1.0.0") + VERSION="${LATEST_TAG#v}-manual-${GITHUB_RUN_NUMBER}" + BUILD_TYPE="manual" + IS_RELEASE="false" + echo "๐Ÿ‘ค Manual build version: ${VERSION}" + elif [[ "${GITHUB_EVENT_NAME}" == "workflow_run" ]]; then + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v1.0.0") + VERSION="${LATEST_TAG#v}-post-validation-${GITHUB_RUN_NUMBER}" + BUILD_TYPE="validated" + IS_RELEASE="false" + echo "โœ… Post-validation build version: ${VERSION}" + else + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v1.0.0") + VERSION="${LATEST_TAG#v}" + BUILD_TYPE="weekly" + IS_RELEASE="false" + echo "๐Ÿ“… Weekly build version: ${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" + + - 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 + runs-on: ubuntu-latest + needs: determine-version + # Only run if validation succeeded when triggered by workflow_run + if: | + github.event_name != 'workflow_run' || + github.event.workflow_run.conclusion == 'success' + steps: + - name: ๐Ÿ“ฅ Checkout Repository uses: actions/checkout@v5 - - name: ๐Ÿณ Lint Dockerfile with Hadolint - uses: hadolint/hadolint-action@v3.1.0 - with: - dockerfile: Dockerfile - failure-threshold: warning - - - name: ๐Ÿ” Validate Dockerfile Syntax + - name: ๐ŸŽฏ Verify Shell Script Extensions run: | - echo "๐Ÿณ Validating Dockerfile build context..." - docker build --no-cache --target builder -t tor-relay-test . 2>&1 | \ - tee /tmp/docker-build.log || true - if grep -i "error" /tmp/docker-build.log; then - echo "โŒ Dockerfile validation failed" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + echo "๐Ÿ“ Pre-Build: Verifying .sh Extensions" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + echo "" + + if [ ! -d "tools" ]; then + echo "โŒ tools/ directory not found" exit 1 fi - echo "โœ… Dockerfile syntax valid" - - name: ๐Ÿ“ Lint Shell Scripts - run: | - echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" - echo "๐Ÿ” Checking Shell Script Syntax" - echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" - echo "" - - # Check main entrypoint script - if [ -f docker-entrypoint.sh ]; then - echo "๐Ÿ“„ Checking docker-entrypoint.sh..." - bash -n docker-entrypoint.sh || exit 1 - echo " โœ… docker-entrypoint.sh syntax valid" - fi - - # Check integration test script - if [ -f integration-check.sh ]; then - echo "๐Ÿ“„ Checking integration-check.sh..." - bash -n integration-check.sh || exit 1 - echo " โœ… integration-check.sh syntax valid" - fi - - echo "" - echo "๐Ÿ“ Checking tools directory (.sh files)..." - - # Check if tools directory exists and has .sh files - if [ ! -d "tools" ]; then - echo " โš ๏ธ tools/ directory not found" - elif [ -z "$(find tools -maxdepth 1 -type f -name '*.sh' 2>/dev/null)" ]; then - echo " โš ๏ธ No .sh files found in tools/" - else - # Check all .sh files in tools/ - TOOL_COUNT=0 - for script in tools/*.sh; do - [ -f "$script" ] || continue - echo "๐Ÿ“„ Checking $(basename "$script")..." - bash -n "$script" || exit 1 - echo " โœ… $script syntax valid" - TOOL_COUNT=$((TOOL_COUNT + 1)) - done - echo "" - echo " โœ… All $TOOL_COUNT tool scripts validated" - fi - - echo "" - echo "๐ŸŽ‰ Shell script syntax validation complete" - - - name: ๐Ÿ”ง Install ShellCheck - run: | - sudo apt-get update - sudo apt-get install -y shellcheck - - - name: ๐Ÿ”Ž Run ShellCheck on Scripts - run: | - echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" - echo "๐Ÿ”Ž Running ShellCheck Static Analysis" - echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" - echo "" - - # ShellCheck main scripts - if [ -f docker-entrypoint.sh ]; then - echo "๐Ÿ” ShellCheck: docker-entrypoint.sh" - shellcheck -S warning docker-entrypoint.sh || true - fi - - if [ -f integration-check.sh ]; then - echo "๐Ÿ” ShellCheck: integration-check.sh" - shellcheck -S warning integration-check.sh || true - fi - - # ShellCheck all .sh files in tools/ - if [ -d "tools" ]; then - echo "" - echo "๐Ÿ” ShellCheck: tools/*.sh" - find tools -maxdepth 1 -type f -name "*.sh" -exec shellcheck -S warning {} \; || true - fi - - echo "" - echo "โœ… ShellCheck analysis complete" - - - name: ๐ŸŽฏ Verify Tool Extensions - run: | - echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" - echo "๐Ÿ“ Verifying Tool File Extensions" - echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" - echo "" - - if [ ! -d "tools" ]; then - echo "โš ๏ธ tools/ directory not found - skipping check" - exit 0 - fi - MISSING_EXT=0 - NON_SH_COUNT=0 SH_COUNT=0 - - # Check all files in tools/ + for file in tools/*; do [ -f "$file" ] || continue - filename=$(basename "$file") extension="${filename##*.}" - + # Check if it's a shell script (has shebang) if head -1 "$file" 2>/dev/null | grep -q "^#!/"; then if [ "$extension" != "sh" ]; then echo "โŒ Shell script missing .sh extension: $filename" MISSING_EXT=1 else + echo "โœ… $filename" SH_COUNT=$((SH_COUNT + 1)) fi - else - NON_SH_COUNT=$((NON_SH_COUNT + 1)) - echo "โ„น๏ธ Non-script file: $filename" fi done - + echo "" - echo "๐Ÿ“Š Summary:" - echo " โ€ข Shell scripts with .sh: $SH_COUNT" - [ $NON_SH_COUNT -gt 0 ] && echo " โ€ข Other files: $NON_SH_COUNT" - echo "" - if [ $MISSING_EXT -eq 1 ]; then - echo "โŒ Some shell scripts are missing .sh extension" + echo "โŒ Build blocked: Some shell scripts missing .sh extension" exit 1 else - echo "โœ… All shell scripts have proper .sh extension" + echo "๐ŸŽ‰ All $SH_COUNT shell scripts have proper .sh extension" fi - - name: ๐Ÿ“‹ Lint YAML Files + - name: ๐Ÿ”ง Normalize scripts before build run: | - echo "๐Ÿ”ง Installing yamllint..." - pip install yamllint - echo "๐Ÿ“‹ Validating YAML files..." - echo "๐Ÿ“ Checking templates (lenient rules)..." - for yaml in templates/*.yml; do - if [ -f "$yaml" ]; then - yamllint -d "{extends: relaxed, rules: {line-length: {max: 200}, \ - trailing-spaces: disable, new-line-at-end-of-file: disable, \ - comments: disable}}" "$yaml" && echo "โœ… $yaml valid" || \ - echo "โš ๏ธ $yaml has warnings (non-blocking)" + 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 integration-check.sh Dockerfile; do + if [ -f "$script" ]; then + dos2unix "$script" 2>/dev/null || true + echo " โœ… Normalized: $script" fi done - echo "๐Ÿ”„ Checking workflows (strict rules)..." - for yaml in .github/workflows/*.yml; do - if [ -f "$yaml" ]; then - yamllint -d relaxed "$yaml" || exit 1 - echo "โœ… $yaml syntax valid" - fi - done - if [ -f ".github/dependabot.yml" ]; then - yamllint -d relaxed .github/dependabot.yml || exit 1 - echo "โœ… .github/dependabot.yml syntax valid" - fi - if [ -d "docs" ]; then - echo "๐Ÿ“š Checking docs (lenient)..." - for yaml in docs/*.yml; do - if [ -f "$yaml" ]; then - yamllint -d "{extends: relaxed, rules: {line-length: {max: 200}, \ - trailing-spaces: disable}}" "$yaml" && echo "โœ… $yaml valid" || \ - echo "โš ๏ธ $yaml has warnings" - fi - done + + echo "" + echo "๐Ÿ“ Processing tools/*.sh..." + if [ -d "tools" ]; then + find tools -type f -name "*.sh" -exec dos2unix {} \; 2>/dev/null || true + TOOL_COUNT=$(find tools -type f -name "*.sh" | wc -l) + echo " โœ… Normalized: $TOOL_COUNT tool scripts" fi - - name: ๐Ÿ”– Validate JSON Files - run: | - echo "๐Ÿ” Validating JSON files..." - for json in templates/*.json examples/*.json .github/*.json; do - if [ -f "$json" ]; then - python3 -m json.tool "$json" > /dev/null || exit 1 - echo "โœ… $json syntax valid" - fi - done + echo "" + echo "๐Ÿ” Setting execute permissions..." + chmod +x docker-entrypoint.sh integration-check.sh 2>/dev/null || true + [ -d "tools" ] && chmod +x tools/*.sh 2>/dev/null || true - - name: ๐Ÿ“š Check Documentation - run: | - echo "๐Ÿ“– Verifying required documentation files..." - required_docs=( - "README.md" - "CHANGELOG.md" - "SECURITY.md" - "CONTRIBUTING.md" - "CODE_OF_CONDUCT.md" - "LICENSE.txt" - ) - for doc in "${required_docs[@]}"; do - if [ ! -f "$doc" ]; then - echo "โŒ Missing documentation: $doc" - exit 1 - fi - echo "โœ… $doc exists" - done - if [ -d "docs" ]; then - echo "๐Ÿ“ Checking docs directory..." - for doc in DEPLOYMENT.md BACKUP.md PERFORMANCE.md LEGAL.md MONITORING.md TOOLS.md; do - if [ -f "docs/$doc" ]; then - echo "โœ… docs/$doc exists" - else - echo "โ„น๏ธ docs/$doc missing (optional)" - fi - done - fi + echo " โœ… Permissions verified" + echo "" + echo "๐ŸŽ‰ Normalization complete" - - name: โœ… Lint Summary - run: echo "๐ŸŽ‰ All linting checks passed" + - name: ๐Ÿณ Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} - build: - name: ๐Ÿ—๏ธ Build Docker Image - runs-on: ubuntu-latest - needs: lint - - steps: - - name: ๐Ÿ“ฅ Checkout Repository - uses: actions/checkout@v5 + - name: ๐Ÿ“ฆ Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.GHCR_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: ๐Ÿ–ฅ๏ธ Set up QEMU uses: docker/setup-qemu-action@v3 with: platforms: arm64,amd64 - - name: ๐Ÿ”ง Set up Docker Buildx + - name: ๐Ÿ”จ Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: ๐Ÿณ Build Image (amd64 for testing) + - name: ๐Ÿท๏ธ Generate Docker Tags + id: tags + run: | + VERSION="${{ needs.determine-version.outputs.version }}" + BUILD_TYPE="${{ needs.determine-version.outputs.build_type }}" + SHORT_SHA="${{ needs.determine-version.outputs.short_sha }}" + TAGS="" + if [ "$BUILD_TYPE" = "release" ]; then + TAGS="${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:latest,${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${VERSION},${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${VERSION}-${SHORT_SHA},${{ env.DOCKERHUB_IMAGE_NAME }}:latest,${{ env.DOCKERHUB_IMAGE_NAME }}:${VERSION},${{ env.DOCKERHUB_IMAGE_NAME }}:${VERSION}-${SHORT_SHA}" + elif [ "$BUILD_TYPE" = "weekly" ]; then + TAGS="${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${VERSION}-weekly,${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${VERSION}-${SHORT_SHA},${{ env.DOCKERHUB_IMAGE_NAME }}:${VERSION}-weekly,${{ env.DOCKERHUB_IMAGE_NAME }}:${VERSION}-${SHORT_SHA}" + elif [ "$BUILD_TYPE" = "validated" ]; then + TAGS="${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${VERSION}-validated,${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${VERSION}-${SHORT_SHA},${{ env.DOCKERHUB_IMAGE_NAME }}:${VERSION}-validated,${{ env.DOCKERHUB_IMAGE_NAME }}:${VERSION}-${SHORT_SHA}" + else + TAGS="${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${VERSION},${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${VERSION}-${SHORT_SHA},${{ env.DOCKERHUB_IMAGE_NAME }}:${VERSION},${{ env.DOCKERHUB_IMAGE_NAME }}:${VERSION}-${SHORT_SHA}" + fi + echo "tags=${TAGS}" >> "$GITHUB_OUTPUT" + + - name: ๐Ÿš€ Build and Push Multi-Arch Image uses: docker/build-push-action@v6 with: context: . file: ./Dockerfile - platforms: linux/amd64 - load: true - tags: tor-relay:test + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.tags.outputs.tags }} build-args: | - BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') - BUILD_VERSION=test-${{ github.run_number }} + BUILD_DATE=${{ needs.determine-version.outputs.build_date }} + BUILD_VERSION=${{ needs.determine-version.outputs.version }} cache-from: type=gha cache-to: type=gha,mode=max + labels: | + org.opencontainers.image.title=Tor Guard Relay + org.opencontainers.image.description=Hardened Tor Guard Relay with diagnostics + org.opencontainers.image.version=${{ needs.determine-version.outputs.version }} + 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 }} - - name: ๐Ÿ’พ Save Image for Testing - run: | - docker save tor-relay:test -o /tmp/tor-relay-test.tar - echo "๐Ÿ“ฆ Image size: $(du -h /tmp/tor-relay-test.tar | cut -f1)" - - - name: โฌ†๏ธ Upload Image Artifact - uses: actions/upload-artifact@v4 - with: - name: docker-image - path: /tmp/tor-relay-test.tar - retention-days: 1 - - integration: - name: ๐Ÿงช Integration Tests + validate: + name: โœ… Validate Build runs-on: ubuntu-latest - needs: build - + needs: [determine-version, build-and-push] steps: - name: ๐Ÿ“ฅ Checkout Repository uses: actions/checkout@v5 - - name: โฌ‡๏ธ Download Docker Image - uses: actions/download-artifact@v4 + - name: ๐Ÿ”‘ Login to Registries + uses: docker/login-action@v3 with: - name: docker-image - path: /tmp + registry: ${{ env.GHCR_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - - name: ๐Ÿ“ฆ Load Docker Image + - name: ๐Ÿ” Validate Images run: | - docker load -i /tmp/tor-relay-test.tar - docker image ls tor-relay - - - name: ๐Ÿš€ Run Container Smoke Test - run: | - echo "๐Ÿš€ Starting container for smoke test..." - docker run -d --name tor-test -e ENABLE_METRICS=true \ - -e ENABLE_HEALTH_CHECK=true tor-relay:test \ - /bin/sh -c "echo 'Test mode active'; sleep 60" || true - sleep 5 - - - name: ๐Ÿ” Check Container Status - run: | - echo "๐Ÿ“Š Container status:" - docker ps -a | grep tor-test || true + set -e + VERSION="${{ needs.determine-version.outputs.version }}" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + echo "โœ… Validating Published Images" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "" - echo "๐Ÿ“‹ Container logs:" - docker logs tor-test 2>&1 | head -30 || true - - name: ๐Ÿ”ง Verify Tools Installation - run: | - echo "๐Ÿ” Checking installed tools..." - docker run --rm tor-relay:test ls -la /usr/local/bin/ || exit 1 - echo "" - echo "๐Ÿ› ๏ธ Available diagnostic tools:" - docker run --rm tor-relay:test sh -c "ls -1 /usr/local/bin/*.sh 2>/dev/null | \ - xargs -n1 basename | sort" + for REG in "${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}" "${{ env.DOCKERHUB_IMAGE_NAME }}"; do + IMAGE_TAG="${REG}:${VERSION}" + echo "๐Ÿ” Testing: $IMAGE_TAG" + docker pull "$IMAGE_TAG" - - name: ๐Ÿง… Verify Tor Installation - run: | - echo "๐Ÿ” Checking Tor version..." - TOR_VERSION=$(docker run --rm tor-relay:test tor --version | head -1) - if [ -z "$TOR_VERSION" ]; then - echo "โŒ Tor installation failed" - exit 1 - fi - echo "โœ… Tor installed: $TOR_VERSION" + echo " ๐Ÿ“ฆ Checking Tor installation..." + TOR_VERSION=$(docker run --rm "$IMAGE_TAG" tor --version | head -1) + echo " โœ… $TOR_VERSION" - - name: ๐Ÿ“ Verify File Structure - run: | - docker run --rm tor-relay:test sh -c " - echo '๐Ÿ“‚ === Directory Structure ===' && \ - ls -la / | grep -E 'var|etc|usr' && \ - echo '' && \ - echo '๐Ÿ› ๏ธ === Tools Directory ===' && \ - ls -la /usr/local/bin/ && \ - echo '' && \ - echo '๐Ÿ’พ === Data Directory ===' && \ - ls -la /var/lib/tor 2>/dev/null || echo '(data dir empty, expected)' && \ - echo '' && \ - echo '๐Ÿ“ === Log Directory ===' && \ - ls -la /var/log/tor 2>/dev/null || echo '(log dir empty, expected)' - " + echo " ๐Ÿ”ง Checking tools..." + TOOL_COUNT=$(docker run --rm "$IMAGE_TAG" sh -c "ls -1 /usr/local/bin/*.sh 2>/dev/null | wc -l") + echo " โœ… Found $TOOL_COUNT tool scripts" - - name: ๐Ÿ“‹ Check Build Metadata - run: | - echo "๐Ÿ” Checking build metadata..." - docker run --rm tor-relay:test cat /build-info.txt || exit 1 - - - name: ๐Ÿ” Verify Permissions - run: | - echo "๐Ÿ” Verifying directory permissions..." - docker run --rm tor-relay:test sh -c " - ls -ld /var/lib/tor | grep -q '^d.*tor tor' && \ - echo 'โœ… /var/lib/tor permissions correct' || exit 1 - ls -ld /var/log/tor | grep -q '^d.*tor tor' && \ - echo 'โœ… /var/log/tor permissions correct' || exit 1 - " - - - name: โœ… Integration Tests Summary - run: echo "๐ŸŽ‰ Integration tests completed successfully" - - - name: ๐Ÿงน Cleanup - if: always() - run: | - docker stop tor-test 2>/dev/null || true - docker rm tor-test 2>/dev/null || true - - security: - name: ๐Ÿ›ก๏ธ Security Scan - runs-on: ubuntu-latest - needs: build - - steps: - - name: ๐Ÿ“ฅ Checkout Repository - uses: actions/checkout@v5 - - - name: โฌ‡๏ธ Download Docker Image - uses: actions/download-artifact@v4 - with: - name: docker-image - path: /tmp - - - name: ๐Ÿ“ฆ Load Docker Image - run: docker load -i /tmp/tor-relay-test.tar - - - name: ๐Ÿ”’ Trivy Security Scan - uses: aquasecurity/trivy-action@master - with: - image-ref: 'tor-relay:test' - format: 'sarif' - output: 'trivy-results.sarif' - severity: 'CRITICAL,HIGH' - - - name: โฌ†๏ธ Upload Trivy Results - uses: github/codeql-action/upload-sarif@v3 - with: - sarif_file: 'trivy-results.sarif' - continue-on-error: true - - - name: ๐Ÿ“Š Trivy Vulnerability Report - uses: aquasecurity/trivy-action@master - with: - image-ref: 'tor-relay:test' - format: 'table' - severity: 'CRITICAL,HIGH' - - - name: โœ… Security Scan Complete - run: echo "๐ŸŽ‰ Security scan completed" - - test-matrix: - name: ๐Ÿงช Test Matrix - runs-on: ubuntu-latest - needs: build - - strategy: - fail-fast: false - matrix: - test-case: - - 'help-flags' - - 'file-permissions' - - 'alpine-compatibility' - - 'tool-executability' - - steps: - - name: ๐Ÿ“ฅ Checkout Repository - uses: actions/checkout@v5 - - - name: โฌ‡๏ธ Download Docker Image - uses: actions/download-artifact@v4 - with: - name: docker-image - path: /tmp - - - name: ๐Ÿ“ฆ Load Docker Image - run: docker load -i /tmp/tor-relay-test.tar - - - name: "๐Ÿ” Test: Help Flags" - if: matrix.test-case == 'help-flags' - run: | - echo "๐Ÿงช Testing tool help flags..." - for tool in health.sh metrics.sh status.sh fingerprint.sh view-logs.sh \ - net-check.sh setup.sh dashboard.sh; do - TOOL_PATH="/usr/local/bin/$tool" - if docker run --rm tor-relay:test sh -c "test -f $TOOL_PATH"; then - echo "๐Ÿ” Testing $tool --help..." - docker run --rm tor-relay:test $tool --help > /dev/null && \ - echo "โœ… $tool --help works" || \ - echo "โš ๏ธ $tool --help failed (non-critical)" - else - echo "โš ๏ธ $tool not found at $TOOL_PATH" - fi + echo "" done - - name: "๐Ÿ” Test: File Permissions" - if: matrix.test-case == 'file-permissions' - run: | - echo "๐Ÿ” Verifying file permissions for .sh tools..." - docker run --rm tor-relay:test sh -c " - for tool in /usr/local/bin/*.sh; do - if [ -f \"\$tool\" ]; then - test -x \"\$tool\" && echo \"โœ… \$(basename \$tool) is executable\" || exit 1 - fi - done - " - docker run --rm tor-relay:test sh -c " - test -x /usr/local/bin/docker-entrypoint.sh && \ - echo 'โœ… docker-entrypoint.sh is executable' || exit 1 - " + echo "๐ŸŽ‰ All images validated successfully" - - name: "๐Ÿ”๏ธ Test: Alpine Compatibility" - if: matrix.test-case == 'alpine-compatibility' - run: | - echo "๐Ÿ”๏ธ Verifying Alpine base image..." - docker run --rm tor-relay:test sh -c " - cat /etc/os-release | grep -i alpine && \ - echo 'โœ… Alpine base confirmed' || exit 1 - test -x /bin/sh && echo 'โœ… /bin/sh available' || exit 1 - apk --version > /dev/null 2>&1 && echo 'โœ… apk available' || exit 1 - command -v tor > /dev/null 2>&1 && echo 'โœ… tor available' || exit 1 - " + release-notes: + name: ๐Ÿ“ Generate Release Notes + runs-on: ubuntu-latest + needs: [determine-version, build-and-push, validate] + if: needs.determine-version.outputs.is_release == 'true' + steps: + - name: ๐Ÿ“ฅ Checkout Repository + uses: actions/checkout@v5 - - name: "๐Ÿ”ง Test: Tool Executability" - if: matrix.test-case == 'tool-executability' + - name: ๐Ÿ“ Generate Notes run: | - echo "๐Ÿ”ง Testing tool execution..." - docker run --rm tor-relay:test sh -c " - for tool in /usr/local/bin/*.sh; do - if [ -f \"\$tool\" ]; then - BASENAME=\$(basename \"\$tool\") - echo \"๐Ÿ” Testing \$BASENAME...\" - \"\$tool\" --help > /dev/null 2>&1 || \ - echo \" โš ๏ธ \$BASENAME --help failed (may require Tor process)\" - fi - done - " + VERSION="${{ needs.determine-version.outputs.version }}" + echo "## ๐Ÿง… Tor Guard Relay v${VERSION} Release Notes" > release_notes.md + echo "" >> release_notes.md + if [ -f CHANGELOG.md ]; then + awk "/## \\[${VERSION}\\]/,0" CHANGELOG.md >> release_notes.md || true + else + echo "See [commit history](https://github.com/${{ github.repository }}/commits/v${VERSION}) for details." >> release_notes.md + fi + echo "" >> release_notes.md + echo "### ๐Ÿณ Docker Images" >> release_notes.md + echo "\`\`\`bash" >> release_notes.md + echo "# ๐Ÿ“ฆ From GHCR:" >> release_notes.md + echo "docker pull ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${VERSION}" >> release_notes.md + echo "" >> release_notes.md + echo "# ๐Ÿณ From Docker Hub:" >> release_notes.md + echo "docker pull ${{ env.DOCKERHUB_IMAGE_NAME }}:${VERSION}" >> release_notes.md + echo "\`\`\`" >> release_notes.md + + - 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 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} summary: name: ๐Ÿ“Š Build Summary runs-on: ubuntu-latest - needs: [lint, build, integration, security, test-matrix] + needs: [determine-version, build-and-push, validate] if: always() - steps: - - name: ๐Ÿ“‹ Generate Build Summary + - name: ๐Ÿ“‹ Generate Summary run: | - cat >> $GITHUB_STEP_SUMMARY << EOF - # ๐Ÿง… Build and Validation Pipeline + VERSION="${{ needs.determine-version.outputs.version }}" + BUILD_TYPE="${{ needs.determine-version.outputs.build_type }}" + BUILD_DATE="${{ needs.determine-version.outputs.build_date }}" + SHORT_SHA="${{ needs.determine-version.outputs.short_sha }}" - ## ๐Ÿ“Š Pipeline Status - - **๐Ÿ” Lint:** \`${{ needs.lint.result }}\` - - **๐Ÿ—๏ธ Build:** \`${{ needs.build.result }}\` - - **๐Ÿงช Integration:** \`${{ needs.integration.result }}\` - - **๐Ÿ›ก๏ธ Security:** \`${{ needs.security.result }}\` - - **๐Ÿงช Test Matrix:** \`${{ needs.test-matrix.result }}\` + echo "# ๐Ÿง… Tor Guard Relay Build Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## ๐Ÿ“ฆ Build Information" >> $GITHUB_STEP_SUMMARY + echo "- **๐Ÿท๏ธ Version:** \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY + echo "- **๐Ÿ“ Build Type:** \`${BUILD_TYPE}\`" >> $GITHUB_STEP_SUMMARY + echo "- **๐Ÿ”‘ Git SHA:** \`${SHORT_SHA}\`" >> $GITHUB_STEP_SUMMARY + echo "- **๐Ÿ“… Build Date:** \`${BUILD_DATE}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## ๐Ÿš€ Published To" >> $GITHUB_STEP_SUMMARY + echo "- ๐Ÿ“ฆ GitHub Container Registry (GHCR)" >> $GITHUB_STEP_SUMMARY + echo "- ๐Ÿณ Docker Hub" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY - ## ๐Ÿ“ฆ Build Information - - **๐ŸŒฟ Branch:** \`${{ github.ref }}\` - - **๐Ÿ“ Commit:** \`${{ github.sha }}\` - - **๐Ÿ”ข Run Number:** \`${{ github.run_number }}\` - - **๐Ÿ“… Date:** \`$(date -u +'%Y-%m-%dT%H:%M:%SZ')\` + if [ "${{ needs.build-and-push.result }}" = "success" ]; then + echo "## ๐ŸŽฏ Pull Commands" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY + echo "# ๐Ÿ“ฆ From GHCR:" >> $GITHUB_STEP_SUMMARY + echo "docker pull ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${VERSION}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "# ๐Ÿณ From Docker Hub:" >> $GITHUB_STEP_SUMMARY + echo "docker pull ${{ env.DOCKERHUB_IMAGE_NAME }}:${VERSION}" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + fi - ## โœ… Checks Performed - - ๐Ÿณ Dockerfile validation with Hadolint - - ๐Ÿ“ Shell script syntax checking (all .sh files) - - ๐ŸŽฏ Shell script extension verification - - ๐Ÿ”Ž ShellCheck static analysis - - ๐Ÿ“‹ YAML validation (lenient for templates) - - ๐Ÿ”– JSON validation - - ๐Ÿ“š Documentation verification - - ๐Ÿ—๏ธ Docker image build (multi-arch ready) - - ๐Ÿš€ Container smoke test - - ๐Ÿง… Tor installation verification - - ๐Ÿ”ง Tool availability check (.sh files) - - ๐Ÿ” Permission verification - - ๐Ÿ›ก๏ธ Security scanning with Trivy - - ๐Ÿงช Test matrix execution - - ## ๐Ÿš€ Next Steps - If all checks pass: - - โœ… Image is ready for production use - - ๐Ÿ“ฆ Release workflow will handle publishing to GHCR and Docker Hub - - ๐Ÿท๏ธ Tag with semantic version to trigger release - EOF - - - name: โœ… Build Pipeline Complete - if: success() - run: echo "๐ŸŽ‰ All build and validation checks passed successfully" - - - name: โŒ Build Pipeline Failed - if: failure() - run: | - echo "โŒ Build pipeline failed - check logs above for details" - exit 1 \ No newline at end of file + echo "" >> $GITHUB_STEP_SUMMARY + echo "## โœ… Validation Results" >> $GITHUB_STEP_SUMMARY + echo "- **๐ŸŽฏ Shell Extension Check:** โœ… Passed" >> $GITHUB_STEP_SUMMARY + echo "- **๐Ÿ”ง Line Ending Normalization:** โœ… Complete" >> $GITHUB_STEP_SUMMARY + echo "- **๐Ÿ—๏ธ Multi-Arch Build:** โœ… AMD64 + ARM64" >> $GITHUB_STEP_SUMMARY + echo "- **๐Ÿ” Image Validation:** \`${{ needs.validate.result }}\`" >> $GITHUB_STEP_SUMMARY