name: โœ…โŒ› on: workflow_dispatch: pull_request: branches: - main - develop push: branches: - main - develop paths: - 'Dockerfile' - 'docker-entrypoint.sh' - 'tools/*' - '.github/workflows/release.yml' - '.github/workflows/validate.yml' - 'templates/**' - 'compose*.yml' - 'docker-compose*.yml' - '.github/dependabot.yml' - '.github/renovate.json' - '!**/*.md' - '!**/*.txt' - '!docs/**' - '!LICENSE*' - '!CONTRIBUTING*' - '!CHANGELOG.md' - '!SECURITY.md' - '!CODE_OF_CONDUCT.md' permissions: contents: read jobs: lint: name: ๐Ÿ” Lint and Validate runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v5 - name: ๐Ÿณ Lint Dockerfile with Hadolint uses: hadolint/hadolint-action@v3.3.0 with: dockerfile: Dockerfile failure-threshold: warning continue-on-error: true - name: ๐Ÿ” Validate Dockerfile Syntax run: | echo "๐Ÿณ Validating Dockerfile build context..." docker build --no-cache -t tor-relay-test . 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..." sh -n docker-entrypoint.sh || exit 1 echo " โœ… docker-entrypoint.sh syntax valid" fi echo "" echo "๐Ÿ“ Checking tools directory (no .sh extension)..." # Check if tools directory exists if [ ! -d "tools" ]; then echo " โš ๏ธ tools/ directory not found" else # Check all files in tools/ (no .sh extension) TOOL_COUNT=0 for script in tools/status tools/health tools/fingerprint tools/bridge-line tools/gen-auth tools/gen-family; do if [ -f "$script" ]; then echo "๐Ÿ“„ Checking $(basename "$script")..." sh -n "$script" || exit 1 echo " โœ… $script syntax valid" TOOL_COUNT=$((TOOL_COUNT + 1)) fi 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 # ShellCheck all tools (no .sh extension) if [ -d "tools" ]; then echo "" echo "๐Ÿ” ShellCheck: tools/*" for tool in tools/status tools/health tools/fingerprint tools/bridge-line tools/gen-auth tools/gen-family; do if [ -f "$tool" ]; then echo " Checking $(basename $tool)..." shellcheck -S warning "$tool" || true fi done fi echo "" echo "โœ… ShellCheck analysis complete" - name: ๐ŸŽฏ Verify Tool Extensions run: | echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "๐Ÿ“ Verifying Tool File Extensions (NO .sh)" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "" if [ ! -d "tools" ]; then echo "โš ๏ธ tools/ directory not found - skipping check" exit 0 fi HAS_SH_EXT=0 NO_EXT_COUNT=0 # Check all files in tools/ for file in tools/*; do [ -f "$file" ] || continue filename=$(basename "$file") # Check if it's a shell script (has shebang) if head -1 "$file" 2>/dev/null | grep -q "^#!/"; then # Tools should NOT have .sh extension if echo "$filename" | grep -q '\.sh$'; then echo "โŒ Tool should NOT have .sh extension: $filename" HAS_SH_EXT=1 else NO_EXT_COUNT=$((NO_EXT_COUNT + 1)) echo "โœ… Tool has correct format (no .sh): $filename" fi fi done echo "" echo "๐Ÿ“Š Summary:" echo " โ€ข Tools without .sh extension: $NO_EXT_COUNT" echo "" if [ $HAS_SH_EXT -eq 1 ]; then echo "โŒ Some tools have .sh extension (should not have it)" exit 1 elif [ $NO_EXT_COUNT -lt 5 ]; then echo "โŒ Expected 6 tools (status, health, fingerprint, bridge-line, gen-auth, gen-family)" exit 1 else echo "โœ… All tools have correct format (no .sh extension)" fi - name: ๐Ÿ“‹ Lint YAML Files 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)" fi done echo "๐Ÿ”„ Checking other YAML files (strict rules)..." for yaml in .github/*.yml; do if [ -f "$yaml" ]; then yamllint -d relaxed "$yaml" || exit 1 echo "โœ… $yaml syntax valid" fi done 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 fi echo "โ„น๏ธ Skipping workflow files validation (complex format)" - 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 - 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 ARCHITECTURE.md BACKUP.md CONTROL-PORT.md DEPLOYMENT.md FAQ.md LEGAL.md LOCAL-TESTING.md MIGRATION-V1.1.X.md MIGRATION.md MONITORING.md MULTI-MODE.md PERFORMANCE.md TOOLS.md TROUBLESHOOTING-BRIDGE-MIGRATION.md; do if [ -f "docs/$doc" ]; then echo "โœ… docs/$doc exists" else echo "โ„น๏ธ docs/$doc missing (optional)" fi done fi - name: โœ… Lint Summary run: echo "๐ŸŽ‰ All linting checks passed" build: name: ๐Ÿ—๏ธ Build Docker Image runs-on: ubuntu-latest needs: lint steps: - name: ๐Ÿ“ฅ Checkout Repository uses: actions/checkout@v5 - name: ๐Ÿ–ฅ๏ธ Set up QEMU uses: docker/setup-qemu-action@v3 with: platforms: arm64,amd64 - name: ๐Ÿ”ง Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: ๐Ÿณ Build Image (amd64 for testing) uses: docker/build-push-action@v6 with: context: . file: ./Dockerfile platforms: linux/amd64 load: true tags: tor-relay:test pull: true build-args: | BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') BUILD_VERSION=test-${{ github.run_number }} cache-from: type=gha cache-to: type=gha,mode=max - 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@v5 with: name: docker-image path: /tmp/tor-relay-test.tar retention-days: 1 integration: name: ๐Ÿงช Integration Tests runs-on: ubuntu-latest needs: build steps: - name: ๐Ÿ“ฅ Checkout Repository uses: actions/checkout@v5 - name: โฌ‡๏ธ Download Docker Image uses: actions/download-artifact@v6 with: name: docker-image path: /tmp - name: ๐Ÿ“ฆ Load Docker Image 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 --entrypoint /bin/sh tor-relay:test \ -c "echo 'โœ… Container started successfully'; sleep 60" || true sleep 5 - name: ๐Ÿ” Check Container Status run: | echo "๐Ÿ“Š Container status:" docker ps -a | grep tor-test || true 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 --entrypoint /bin/sh tor-relay:test -c "ls -la /usr/local/bin/" || exit 1 echo "" echo "๐Ÿ› ๏ธ Available diagnostic tools:" docker run --rm --entrypoint /bin/sh tor-relay:test -c "ls -1 /usr/local/bin/status /usr/local/bin/health /usr/local/bin/fingerprint /usr/local/bin/bridge-line /usr/local/bin/gen-auth /usr/local/bin/gen-family" || exit 1 - name: ๐Ÿง… Verify Tor Installation run: | echo "๐Ÿ” Checking Tor version..." TOR_VERSION=$(docker run --rm --entrypoint tor tor-relay:test --version | head -1) if [ -z "$TOR_VERSION" ]; then echo "โŒ Tor installation failed" exit 1 fi echo "โœ… Tor installed: $TOR_VERSION" - name: ๐Ÿ“ Verify File Structure run: | docker run --rm --entrypoint /bin/sh tor-relay:test -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)' " - name: ๐Ÿ“‹ Check Build Metadata run: | echo "๐Ÿ” Checking build metadata..." docker run --rm --entrypoint cat tor-relay:test /build-info.txt || exit 1 - name: ๐Ÿ” Verify Permissions run: | echo "๐Ÿ” Verifying directory permissions..." docker run --rm --entrypoint /bin/sh tor-relay:test -c " DATA_OWNER=\$(stat -c '%u %g' /var/lib/tor) if [ \"\$DATA_OWNER\" = '100 101' ]; then echo 'โœ… /var/lib/tor ownership correct (100:101)' else echo 'โŒ /var/lib/tor ownership incorrect: \$DATA_OWNER' exit 1 fi LOG_OWNER=\$(stat -c '%u %g' /var/log/tor) if [ \"\$LOG_OWNER\" = '100 101' ]; then echo 'โœ… /var/log/tor ownership correct (100:101)' else echo 'โŒ /var/log/tor ownership incorrect: \$LOG_OWNER' exit 1 fi " - 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 permissions: contents: read security-events: write actions: read steps: - name: ๐Ÿ“ฅ Checkout Repository uses: actions/checkout@v5 - name: โฌ‡๏ธ Download Docker Image uses: actions/download-artifact@v6 with: name: docker-image path: /tmp - name: ๐Ÿ“ฆ Load Docker Image run: docker load -i /tmp/tor-relay-test.tar - name: ๐Ÿ”’ Trivy - Comprehensive Vulnerability Scan uses: aquasecurity/trivy-action@0.34.1 with: image-ref: 'tor-relay:test' format: 'sarif' output: 'trivy-results.sarif' severity: 'CRITICAL,HIGH,MEDIUM' vuln-type: 'os,library' ignore-unfixed: false scanners: 'vuln,secret,config' - name: โฌ†๏ธ Upload Trivy Results to GitHub Security id: upload-sarif uses: github/codeql-action/upload-sarif@v4 with: sarif_file: 'trivy-results.sarif' continue-on-error: true - name: ๐Ÿ“ SARIF Upload Status if: always() run: | if [ "${{ steps.upload-sarif.outcome }}" = "success" ]; then echo "โœ… SARIF results successfully uploaded to GitHub Security tab" echo " View at: ${{ github.server_url }}/${{ github.repository }}/security/code-scanning" else echo "โš ๏ธ SARIF upload skipped or failed (this is non-blocking)" echo "" echo "Possible reasons:" echo " โ€ข Private repository without GitHub Advanced Security" echo " โ€ข Insufficient permissions" echo " โ€ข GitHub API rate limiting" echo "" echo "Security scan results are still available in:" echo " โœ… Human-readable table output (see steps below)" echo " โœ… JSON artifact (trivy-security-report)" fi - name: ๐Ÿ“Š Trivy - Human Readable Report (Critical & High) uses: aquasecurity/trivy-action@0.34.1 with: image-ref: 'tor-relay:test' format: 'table' severity: 'CRITICAL,HIGH' vuln-type: 'os,library' ignore-unfixed: false - name: ๐Ÿ” Trivy - Full Vulnerability List (All Severities) uses: aquasecurity/trivy-action@0.34.1 with: image-ref: 'tor-relay:test' format: 'json' output: 'trivy-full-report.json' severity: 'UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL' vuln-type: 'os,library' continue-on-error: true - name: ๐Ÿ” Trivy - Secret Scanning uses: aquasecurity/trivy-action@0.34.1 with: image-ref: 'tor-relay:test' scanners: 'secret' format: 'table' continue-on-error: true - name: โš™๏ธ Trivy - Configuration Audit uses: aquasecurity/trivy-action@0.34.1 with: image-ref: 'tor-relay:test' scanners: 'config' format: 'table' continue-on-error: true - name: ๐Ÿ—‚๏ธ Trivy - Filesystem Scan uses: aquasecurity/trivy-action@0.34.1 with: scan-type: 'fs' scan-ref: '.' format: 'table' severity: 'CRITICAL,HIGH' scanners: 'vuln,secret,config,license' skip-dirs: '.git,docs,examples,templates' continue-on-error: true - name: โฌ†๏ธ Upload Full Report Artifact uses: actions/upload-artifact@v5 with: name: trivy-security-report path: trivy-full-report.json retention-days: 7 continue-on-error: true - name: ๐Ÿ“‹ Generate Security Summary run: | echo "## ๐Ÿ›ก๏ธ Security Scan Results" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Scans Performed:" >> $GITHUB_STEP_SUMMARY echo "- โœ… Image vulnerability scan (OS packages & libraries)" >> $GITHUB_STEP_SUMMARY echo "- โœ… Secret scanning (API keys, tokens, credentials)" >> $GITHUB_STEP_SUMMARY echo "- โœ… Configuration audit (Dockerfile, security best practices)" >> $GITHUB_STEP_SUMMARY echo "- โœ… Filesystem scan (source code vulnerabilities)" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Report Locations:" >> $GITHUB_STEP_SUMMARY echo "- **GitHub Security Tab:** Detailed SARIF results uploaded" >> $GITHUB_STEP_SUMMARY echo "- **Artifacts:** Full JSON report available for download" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Scan Coverage:" >> $GITHUB_STEP_SUMMARY echo "- **Severity Levels:** CRITICAL, HIGH, MEDIUM, LOW" >> $GITHUB_STEP_SUMMARY echo "- **Scan Types:** Vulnerabilities, Secrets, Configs, Licenses" >> $GITHUB_STEP_SUMMARY echo "- **Databases:** Alpine, NVD, GitHub Advisory" >> $GITHUB_STEP_SUMMARY - name: โœ… Security Scan Complete run: echo "๐ŸŽ‰ Security scan completed - check GitHub Security tab for detailed results" 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@v6 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 existence..." for tool in status health fingerprint bridge-line gen-auth gen-family; do TOOL_PATH="/usr/local/bin/$tool" if docker run --rm --entrypoint /bin/sh tor-relay:test -c "test -f $TOOL_PATH"; then echo "โœ… $tool exists at $TOOL_PATH" else echo "โŒ $tool not found at $TOOL_PATH" exit 1 fi done - name: "๐Ÿ” Test: File Permissions" if: matrix.test-case == 'file-permissions' run: | echo "๐Ÿ” Verifying file permissions for tools..." docker run --rm --entrypoint /bin/sh tor-relay:test -c " for tool in /usr/local/bin/status /usr/local/bin/health /usr/local/bin/fingerprint /usr/local/bin/bridge-line /usr/local/bin/gen-auth /usr/local/bin/gen-family; do if [ -f \"\$tool\" ]; then test -x \"\$tool\" && echo \"โœ… \$(basename \$tool) is executable\" || exit 1 fi done " docker run --rm --entrypoint /bin/sh tor-relay:test -c " test -x /usr/local/bin/docker-entrypoint.sh && \ echo 'โœ… docker-entrypoint.sh is executable' || exit 1 " - name: "๐Ÿ”๏ธ Test: Alpine Compatibility" if: matrix.test-case == 'alpine-compatibility' run: | echo "๐Ÿ”๏ธ Verifying Alpine base image..." docker run --rm --entrypoint /bin/sh tor-relay:test -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 " - name: "๐Ÿ”ง Test: Tool Executability" if: matrix.test-case == 'tool-executability' run: | echo "๐Ÿ”ง Testing tool execution..." docker run --rm --entrypoint /bin/sh tor-relay:test -c " for tool in /usr/local/bin/status /usr/local/bin/health /usr/local/bin/fingerprint /usr/local/bin/bridge-line /usr/local/bin/gen-auth /usr/local/bin/gen-family; do if [ -f \"\$tool\" ]; then BASENAME=\$(basename \"\$tool\") echo \"๐Ÿ” Testing \$BASENAME...\" # Tools require Tor to be running, just verify they're executable test -x \"\$tool\" && echo \" โœ… \$BASENAME is executable\" || exit 1 fi done " summary: name: ๐Ÿ“Š Build Summary runs-on: ubuntu-latest needs: [lint, build, integration, security, test-matrix] if: always() steps: - name: ๐Ÿ“‹ Generate Build Summary run: | cat >> $GITHUB_STEP_SUMMARY << EOF # ๐Ÿง… Build and Validation Pipeline ## ๐Ÿ“Š Pipeline Status - **๐Ÿ” Lint:** \`${{ needs.lint.result }}\` - **๐Ÿ—๏ธ Build:** \`${{ needs.build.result }}\` - **๐Ÿงช Integration:** \`${{ needs.integration.result }}\` - **๐Ÿ›ก๏ธ Security:** \`${{ needs.security.result }}\` - **๐Ÿงช Test Matrix:** \`${{ needs.test-matrix.result }}\` ## ๐Ÿ“ฆ Build Information - **๐ŸŒฟ Branch:** \`${{ github.ref }}\` - **๐Ÿ“ Commit:** \`${{ github.sha }}\` - **๐Ÿ”ข Run Number:** \`${{ github.run_number }}\` - **๐Ÿ“… Date:** \`$(date -u +'%Y-%m-%dT%H:%M:%SZ')\` ## โœ… Checks Performed - ๐Ÿณ Dockerfile validation with Hadolint - ๐Ÿ“ Shell script syntax checking (POSIX sh) - ๐ŸŽฏ Tool extension verification (no .sh) - ๐Ÿ”Ž 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 (status, health, fingerprint, bridge-line, gen-auth, gen-family) - ๐Ÿ” 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