name: Flask CI/CD Pipeline on: push: branches: [ main ] env: IMAGE_NAME: 10.0.2.109:3000/gitea/arcade jobs: format-and-auto-fix: runs-on: ubuntu-latest steps: - name: Check out repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Inspect environment run: | uname -a cat /etc/os-release || true which python || true python --version || true - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.11" - name: Install formatting dependencies run: | python -m venv venv . venv/bin/activate pip install --upgrade pip pip install -r requirements.txt pip install ruff - name: Run Ruff auto-fix and formatting run: | . venv/bin/activate python -m ruff check . --fix --exclude venv,.venv python -m ruff format . --exclude venv,.venv - name: Commit and push formatting changes run: | if [ -n "$(git status --porcelain)" ]; then git config --global user.name "gitea-actions[bot]" git config --global user.email "gitea-actions[bot]@local" git add . git commit -m "Auto-fix code style" git push else echo "No formatting changes to commit" fi test-and-verify: needs: format-and-auto-fix runs-on: ubuntu-latest steps: - name: Check out repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Scan repository and git history for leaked secrets with Gitleaks run: | docker run --rm \ -v "$PWD":/repo \ ghcr.io/gitleaks/gitleaks:latest \ git /repo --verbose - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.11" - name: Install test and security dependencies run: | python -m venv venv . venv/bin/activate pip install --upgrade pip pip install -r requirements.txt pip install pytest pytest-cov pip-audit - name: Run pytest with coverage run: | . venv/bin/activate PYTHONPATH=. pytest --cov=. --cov-report=term-missing - name: Run lightweight input fuzzing against Flask test client run: | . venv/bin/activate python - <<'PY' import random import string from app import app client = app.test_client() samples = [ "", "abc", "🔥", "één test", "", "\x00", " " * 100, "a" * 10000, "🙂🙃😅", "漢字かなカナ", "\n\t\r", ] alphabet = string.ascii_letters + string.digits + string.punctuation + " 🙂🔥éäöü漢字\n\t" for _ in range(100): size = random.randint(0, 512) samples.append("".join(random.choice(alphabet) for _ in range(size))) for value in samples: response = client.post("/", data={"tekst": value}) assert response.status_code == 200, f"Unexpected status code for input length {len(value)}" body = response.get_data(as_text=True) assert "Spiegelbeeld:" in body, "Expected response marker not found" print(f"Lightweight fuzzing completed successfully for {len(samples)} inputs.") PY - name: Scan Python dependencies with pip-audit run: | . venv/bin/activate pip-audit - name: Start Flask app and run smoke test run: | . venv/bin/activate python app.py & APP_PID=$! sleep 5 curl -f http://127.0.0.1:5000 kill $APP_PID build-scan-and-push-image: needs: test-and-verify runs-on: ubuntu-latest steps: - name: Check out repository uses: actions/checkout@v4 - name: Log in to Gitea container registry run: | echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login git.onlionel.com:3000 -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin - name: Build Docker images run: | docker build --pull -t $IMAGE_NAME:latest . docker build --pull -t $IMAGE_NAME:${{ gitea.sha }} . - name: Verify Flask is available in container image run: | docker run --rm $IMAGE_NAME:latest python -c "import flask" - name: Clean up old test containers run: | docker stop arcade-test || true docker rm -f arcade-test || true - name: Install Trivy run: | sudo apt-get update sudo apt-get install -y wget gnupg lsb-release apt-transport-https wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add - echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/trivy.list sudo apt-get update sudo apt-get install -y trivy - name: Scan container image with Trivy run: | trivy image --exit-code 0 --severity HIGH,CRITICAL $IMAGE_NAME:latest - name: Push container images run: | docker push $IMAGE_NAME:latest docker push $IMAGE_NAME:${{ gitea.sha }} deploy-updated-container: needs: build-scan-and-push-image runs-on: ubuntu-latest steps: - name: Redeploy container over SSH uses: appleboy/ssh-action@master with: host: 10.0.2.109 username: ${{ secrets.SSH_USERNAME }} key: ${{ secrets.SSH_PRIVATE_KEY }} script: | cd ~/docker-compose/arcade/ docker compose -f docker-compose.stable.yml down docker compose -f docker-compose.ci.yml pull docker compose -f docker-compose.ci.yml up -d