saap-plattform / .github /workflows /ci-cd-pipeline.yml
Hwandji's picture
feat: initial HuggingFace Space deployment
4343907
raw
history blame
15 kB
name: SAAP CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
release:
types: [ published ]
env:
REGISTRY: ghcr.io
IMAGE_NAME_BACKEND: ${{ github.repository }}/backend
IMAGE_NAME_FRONTEND: ${{ github.repository }}/frontend
jobs:
# ==========================================
# JOB 1: Security Scanning
# ==========================================
security-scan:
name: Security Checks
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Gitleaks
run: |
wget -q https://github.com/gitleaks/gitleaks/releases/download/v8.18.4/gitleaks_8.18.4_linux_x64.tar.gz
tar -xzf gitleaks_8.18.4_linux_x64.tar.gz
sudo mv gitleaks /usr/local/bin/
gitleaks version
- name: Run Gitleaks Scan
run: |
gitleaks detect --source . --config .gitleaks.toml --verbose --no-git
- name: Python Security Check (Safety)
run: |
pip install safety
safety check --file requirements.txt --output text || true
- name: Node.js Security Check (npm audit)
working-directory: ./frontend
run: |
npm install
npm audit --audit-level=moderate || true
# ==========================================
# JOB 2: Backend Testing (Python/FastAPI)
# ==========================================
backend-tests:
name: Backend Tests (Python)
runs-on: ubuntu-latest
needs: security-scan
services:
postgres:
image: postgres:15-alpine
env:
POSTGRES_USER: saap_test
POSTGRES_PASSWORD: test_password
POSTGRES_DB: saap_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pytest pytest-cov pytest-asyncio
- name: Run Backend Tests
env:
DATABASE_URL: postgresql://saap_test:test_password@localhost:5432/saap_test
PYTHONPATH: ${{ github.workspace }}/backend
run: |
pytest backend/ -v --cov=backend --cov-report=xml --cov-report=term
- name: Upload Coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: ./coverage.xml
flags: backend
name: backend-coverage
# ==========================================
# JOB 3: Frontend Testing (Vue.js)
# ==========================================
frontend-tests:
name: Frontend Tests (Vue.js)
runs-on: ubuntu-latest
needs: security-scan
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js 20
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json
- name: Install dependencies
working-directory: ./frontend
run: npm ci
- name: Run ESLint
working-directory: ./frontend
run: npm run lint || true
- name: Run Frontend Tests
working-directory: ./frontend
run: npm run test:unit || echo "No tests configured yet"
- name: Build Frontend
working-directory: ./frontend
run: npm run build
# ==========================================
# JOB 4: Build Docker Images
# ==========================================
build-docker-images:
name: Build Docker Images
runs-on: ubuntu-latest
needs: [backend-tests, frontend-tests]
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Backend
id: meta-backend
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_BACKEND }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix={{branch}}-
- name: Extract metadata (tags, labels) for Frontend
id: meta-frontend
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_FRONTEND }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix={{branch}}-
- name: Build and push Backend Docker image
uses: docker/build-push-action@v5
with:
context: ./backend
file: ./backend/Dockerfile
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta-backend.outputs.tags }}
labels: ${{ steps.meta-backend.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build and push Frontend Docker image
uses: docker/build-push-action@v5
with:
context: ./frontend
file: ./frontend/Dockerfile
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta-frontend.outputs.tags }}
labels: ${{ steps.meta-frontend.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# ==========================================
# JOB 5: Create Deployment Package
# ==========================================
create-deployment-package:
name: Create Local Deployment Package
runs-on: ubuntu-latest
needs: build-docker-images
if: github.event_name == 'release'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Create deployment package
run: |
mkdir -p deployment-package
cp docker-compose.yml deployment-package/
cp docker-compose.prod.yml deployment-package/
cp .env.example deployment-package/.env
cp README.md deployment-package/
cp QUICKSTART.md deployment-package/
# Create deployment instructions
cat > deployment-package/DEPLOYMENT.md << 'EOF'
# SAAP Lokales Deployment
## Voraussetzungen
- Docker 24.0 oder höher
- Docker Compose 2.20 oder höher
- 4 GB RAM minimum
- 10 GB Festplattenspeicher
## Schnellstart
1. **Konfiguration anpassen:**
```bash
cp .env.example .env
# .env-Datei editieren und API-Keys eintragen
```
2. **SAAP starten:**
```bash
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
```
3. **Status überprüfen:**
```bash
docker-compose ps
```
4. **Anwendung öffnen:**
- Frontend: http://localhost:5173
- Backend API: http://localhost:8000
- API Docs: http://localhost:8000/docs
## Verwaltung
- **Logs anzeigen:** `docker-compose logs -f`
- **Neustart:** `docker-compose restart`
- **Stoppen:** `docker-compose down`
- **Updates:** `docker-compose pull && docker-compose up -d`
## Kostenvergleich: Lokal vs. Cloud
| Kriterium | Lokal (SAAP) | AWS/Azure Cloud |
|-----------|--------------|-----------------|
| Monatliche Kosten | €0 (nur Stromkosten) | €200-500+ |
| Datenschutz | Vollständig lokal | Externen Servern |
| Latenz | <10ms | 50-200ms |
| Skalierung | Manuell | Automatisch |
| Wartung | Selbst | Managed |
## Support
Bei Fragen: https://github.com/satwareAG/saap/issues
EOF
- name: Create archive
run: |
cd deployment-package
tar -czf ../saap-deployment-${{ github.ref_name }}.tar.gz .
- name: Upload deployment package
uses: actions/upload-artifact@v4
with:
name: saap-deployment-package
path: saap-deployment-${{ github.ref_name }}.tar.gz
- name: Upload to Release
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: saap-deployment-${{ github.ref_name }}.tar.gz
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# ==========================================
# JOB 6: Deploy to HuggingFace Spaces
# ==========================================
deploy-huggingface:
name: Deploy to HuggingFace Spaces
runs-on: ubuntu-latest
needs: [backend-tests, frontend-tests]
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install HuggingFace Hub
run: pip install huggingface_hub
- name: Debug - Check HF_TOKEN
run: |
if [ -z "${{ secrets.HF_TOKEN }}" ]; then
echo "❌ ERROR: HF_TOKEN secret not configured"
echo "Please add HF_TOKEN to repository secrets"
exit 1
else
echo "✅ HF_TOKEN is configured"
echo "Token length: ${#HF_TOKEN}"
fi
env:
HF_TOKEN: ${{ secrets.HF_TOKEN }}
- name: Prepare deployment files
run: |
echo "📦 Preparing HuggingFace deployment files..."
# Create huggingface deployment directory
mkdir -p huggingface_deploy
# Copy all necessary files
cp -r huggingface/* huggingface_deploy/
cp -r backend huggingface_deploy/
cp -r frontend huggingface_deploy/
cp requirements.txt huggingface_deploy/
# Verify critical files exist
echo "📋 Verifying deployment files:"
ls -la huggingface_deploy/
if [ ! -f "huggingface_deploy/Dockerfile" ]; then
echo "❌ ERROR: Dockerfile missing"
exit 1
fi
if [ ! -f "huggingface_deploy/README.md" ]; then
echo "⚠️ WARNING: README.md missing - creating default"
cat > huggingface_deploy/README.md << 'EOF'
---
title: SAAP - satware AI Autonomous Agent Platform
emoji: 🤖
colorFrom: purple
colorTo: blue
sdk: docker
app_port: 7860
pinned: false
license: mit
---
# SAAP - satware® AI Autonomous Agent Platform
Local autonomous multi-agent system for specialized AI agents.
**Features:**
- Multi-agent coordination (Jane, John, Lara, Theo, Justus, Leon, Luna)
- Real-time WebSocket communication
- Cost-efficient hybrid provider support
- Privacy-first local deployment
EOF
fi
echo "✅ Deployment files prepared"
- name: Upload to HuggingFace Space
env:
HF_TOKEN: ${{ secrets.HF_TOKEN }}
run: |
echo "🚀 Deploying to HuggingFace Spaces..."
cd huggingface_deploy
python << 'DEPLOY_SCRIPT'
import os
import sys
from huggingface_hub import HfApi, create_repo
# Configuration
repo_id = "Hwandji/saap"
token = os.environ.get("HF_TOKEN")
if not token:
print("❌ HF_TOKEN not found")
sys.exit(1)
print(f"📤 Uploading to HuggingFace Space: {repo_id}")
try:
api = HfApi(token=token)
# Upload all files
api.upload_folder(
folder_path=".",
repo_id=repo_id,
repo_type="space",
commit_message=f"Deploy from GitHub Actions - {os.environ.get('GITHUB_SHA', 'unknown')[:7]}"
)
print(" Successfully uploaded to HuggingFace")
print(f"🌐 Space URL: https://huggingface.co/spaces/{repo_id}")
except Exception as e:
print(f"❌ Deployment failed: {e}")
sys.exit(1)
DEPLOY_SCRIPT
- name: Deployment summary
run: |
echo "📊 Deployment Summary"
echo "===================="
echo "✅ Files uploaded to HuggingFace Spaces"
echo "🌐 Space: https://huggingface.co/spaces/Hwandji/saap"
echo "⏳ Note: Space restart may take 2-3 minutes"
echo "🔍 Check logs at: https://huggingface.co/spaces/Hwandji/saap/logs"
# ==========================================
# JOB 7: Deployment Success Notification
# ==========================================
notify-deployment:
name: Deployment Status
runs-on: ubuntu-latest
needs: [build-docker-images, create-deployment-package, deploy-huggingface]
if: always()
steps:
- name: Check deployment status
run: |
if [ "${{ needs.build-docker-images.result }}" = "success" ]; then
echo "✅ Docker Images erfolgreich gebaut"
echo "📦 Images verfügbar in GitHub Container Registry"
echo "🚀 Deployment-Package bereit für lokale Installation"
else
echo "❌ Deployment fehlgeschlagen"
exit 1
fi
if [ "${{ needs.deploy-huggingface.result }}" = "success" ]; then
echo "✅ HuggingFace Deployment erfolgreich"
echo "🌐 Space: https://huggingface.co/spaces/Hwandji/saap"
elif [ "${{ needs.deploy-huggingface.result }}" = "skipped" ]; then
echo "⏭️ HuggingFace Deployment übersprungen (nicht main branch)"
else
echo "❌ HuggingFace Deployment fehlgeschlagen"
fi