mirror of
https://github.com/r3bo0tbx1/tor-guard-relay.git
synced 2026-04-06 00:32:04 +02:00
🔧 New tool: gen-family - generate/view Happy Family keys - Supports --force flag to overwrite existing keys without backup prompt 🐳 Dockerfiles: gen-family in both Dockerfile and Dockerfile.edge 🔧 Entrypoint: - Phase 2: detect *.secret_family_key, log found keys (informational only) - Guard/exit config gen: append FamilyId + MyFamily from ENV vars - Bridge intentionally excluded 📊 Status tool: show family key count + Happy Family config state 📚 Docs: - README: Happy Family section (generate / import), persistence table, flowchart - ARCHITECTURE: all mermaid diagrams updated (Phase 2, config gen, tools, dirs) - TOOLS: full gen-family reference with examples and exit codes - DEPLOYMENT, MIGRATION, MIGRATION-V1.1.X, TROUBLESHOOTING: 5 -> 6 tools - FAQ, example configs: version bump + FamilyId/MyFamily placeholders - Directory authority voting: how 9 dirauths vote on relay flags (5/9 consensus) - CIISS v2 ContactInfo: field reference, generator link, proof:uri-rsa verification - All TOR_CONTACT_INFO examples updated to CIISS v2 format across templates and docs 📋 Templates: - Guard/exit/multi-relay compose: TOR_FAMILY_ID + TOR_MY_FAMILY env vars - All cosmos-compose + docker-compose versions -> 1.1.7 👷 CI: validate.yml gen-family in 8 spots (threshold 6), security tests, quick-test 🛡️ SECURITY.md: 1.1.7 active, 1.1.6 maintenance, gen-family in tools list 🔖 Version bump 1.1.6 -> 1.1.7 across 30+ files, tool count 5 -> 6, CHANGELOG entry No breaking changes. TOR_FAMILY_ID and TOR_MY_FAMILY are optional.
678 lines
24 KiB
YAML
678 lines
24 KiB
YAML
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
|
||
|