name: ✅ Continuous Integration run-name: CI Checks - ${{ github.ref_name || github.head_ref }} on: push: branches-ignore: - main - staging paths-ignore: - '**.md' - 'docs/**' pull_request: branches: - main - staging jobs: tests: name: Run Tests & Quality Checks runs-on: php-ci steps: - name: Download CI helpers shell: bash env: CI_TOKEN: ${{ secrets.CI_TOKEN }} run: | set -euo pipefail REF="${{ github.sha }}" if [ -z "$REF" ]; then REF="${{ github.ref_name }}" fi if [ -z "$REF" ]; then REF="${{ github.head_ref }}" fi if [ -z "$REF" ]; then REF="${{ github.base_ref || 'develop' }}" fi URL="https://git.michaelschiemer.de/${{ github.repository }}/raw/${REF}/scripts/ci/clone_repo.sh" mkdir -p /tmp/ci-tools if [ -n "$CI_TOKEN" ]; then curl -sfL -u "$CI_TOKEN:x-oauth-basic" "$URL" -o /tmp/ci-tools/clone_repo.sh else curl -sfL "$URL" -o /tmp/ci-tools/clone_repo.sh fi chmod +x /tmp/ci-tools/clone_repo.sh - name: Checkout code env: REF_NAME_GITHUB: ${{ github.ref_name }} HEAD_REF: ${{ github.head_ref }} BASE_REF: ${{ github.base_ref }} run: | REF_NAME="$REF_NAME_GITHUB" if [ -z "$REF_NAME" ]; then REF_NAME="$HEAD_REF" fi if [ -z "$REF_NAME" ]; then REF_NAME="$BASE_REF" fi if [ -z "$REF_NAME" ]; then REF_NAME="develop" fi export CI_REPOSITORY="${{ github.repository }}" export CI_TOKEN="${{ secrets.CI_TOKEN }}" export CI_REF_NAME="$REF_NAME" export CI_INPUT_BRANCH="$HEAD_REF" export CI_DEFAULT_BRANCH="develop" export CI_TARGET_DIR="/workspace/repo" export CI_FETCH_DEPTH="1" /tmp/ci-tools/clone_repo.sh cd /workspace/repo # Note: Composer caching via actions/cache@v4 requires Node.js in runner # Skipped for now - vendor/ is cached in runner workspace - name: Install PHP dependencies run: | cd /workspace/repo composer install --no-interaction --prefer-dist --optimize-autoloader --ignore-platform-req=php - name: PHPStan (baseline) run: | cd /workspace/repo make phpstan || echo "⚠️ phpstan skipped/failed" - name: Lint PHP (dry run) run: | cd /workspace/repo make cs || echo "⚠️ php-cs-fixer dry run issues detected" - name: Validate .env.base for secrets run: | cd /workspace/repo if [ -f .env.base ]; then echo "🔍 Checking .env.base for secrets..." # Check for potential secrets (case-insensitive) if grep -qiE "(password|secret|key|token|encryption|vault)" .env.base | grep -v "^#" | grep -v "FILE=" | grep -v "^$$" > /dev/null; then echo "::error::.env.base contains potential secrets! Secrets should be in .env.local or Docker Secrets." echo "⚠️ Found potential secrets in .env.base:" grep -iE "(password|secret|key|token|encryption|vault)" .env.base | grep -v "^#" | grep -v "FILE=" | grep -v "^$$" || true echo "" echo "💡 Move secrets to:" echo " - .env.local (for local development)" echo " - Docker Secrets (for production/staging)" exit 1 else echo "✅ .env.base does not contain secrets" fi else echo "ℹ️ .env.base not found (optional during migration)" fi echo "" echo "🔍 Checking docker-compose.base.yml for hardcoded passwords..." if grep -E "(PASSWORD|SECRET|TOKEN).*:-[^}]*[^}]}" docker-compose.base.yml 2>/dev/null | grep -v "^#" | grep -v "FILE=" > /dev/null; then echo "::error::docker-compose.base.yml contains hardcoded password fallbacks! Passwords must be set explicitly." echo "⚠️ Found hardcoded password fallbacks:" grep -E "(PASSWORD|SECRET|TOKEN).*:-[^}]*[^}]}" docker-compose.base.yml | grep -v "^#" | grep -v "FILE=" || true echo "" echo "💡 Remove fallback values (:-...) from base file" echo " Passwords must be set in .env.local or via Docker Secrets" exit 1 else echo "✅ docker-compose.base.yml does not contain hardcoded password fallbacks" fi - name: Tests temporarily skipped run: | echo "⚠️ Tests temporarily skipped due to PHP 8.5 compatibility issues"