name: Security Vulnerability Scan on: push: branches: [ main, develop ] pull_request: branches: [ main, develop ] schedule: # Daily security scan at 2 AM UTC - cron: '0 2 * * *' workflow_dispatch: jobs: security-audit: name: Composer Security Audit runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup PHP uses: https://github.com/shivammathur/setup-php@v2 with: php-version: '8.4' extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, sodium coverage: none - name: Validate composer.json and composer.lock run: composer validate --strict - name: Cache Composer packages uses: actions/cache@v3 with: path: vendor key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} restore-keys: | ${{ runner.os }}-php- - name: Install dependencies run: composer install --prefer-dist --no-progress --no-dev - name: Run Composer Security Audit id: security-audit run: | composer audit --format=json > audit-result.json || true cat audit-result.json - name: Parse audit results id: parse-audit run: | if [ -f audit-result.json ]; then # Check if jq is available, install if not if ! command -v jq &> /dev/null; then apt-get update && apt-get install -y jq fi ADVISORIES=$(jq -r '.advisories | length' audit-result.json 2>/dev/null || echo "0") ABANDONED=$(jq -r '.abandoned | length' audit-result.json 2>/dev/null || echo "0") echo "advisories_count=$ADVISORIES" >> $GITHUB_OUTPUT echo "abandoned_count=$ABANDONED" >> $GITHUB_OUTPUT echo "## Security Audit Results" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "- **Vulnerabilities Found:** $ADVISORIES" >> $GITHUB_STEP_SUMMARY echo "- **Abandoned Packages:** $ABANDONED" >> $GITHUB_STEP_SUMMARY if [ "$ADVISORIES" -gt 0 ]; then echo "has_vulnerabilities=true" >> $GITHUB_OUTPUT echo "- **Status:** ❌ Security vulnerabilities detected - review required" >> $GITHUB_STEP_SUMMARY # Display vulnerability details echo "" >> $GITHUB_STEP_SUMMARY echo "### Vulnerability Details" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '```json' >> $GITHUB_STEP_SUMMARY jq '.advisories' audit-result.json >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY exit 1 else echo "has_vulnerabilities=false" >> $GITHUB_OUTPUT echo "- **Status:** ✅ No security vulnerabilities detected" >> $GITHUB_STEP_SUMMARY fi if [ "$ABANDONED" -gt 0 ]; then echo "" >> $GITHUB_STEP_SUMMARY echo "### Abandoned Packages" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY jq -r '.abandoned | to_entries[] | "- **\(.key)**: \(.value // "No replacement suggested")"' audit-result.json >> $GITHUB_STEP_SUMMARY fi fi - name: Upload audit results as artifact if: always() uses: actions/upload-artifact@v3 with: name: security-audit-results-${{ github.run_number }} path: audit-result.json retention-days: 30 - name: Create Gitea issue on vulnerability (scheduled runs only) if: failure() && github.event_name == 'schedule' run: | # Prepare issue body ISSUE_TITLE="🚨 Security Vulnerabilities Detected in Dependencies" ISSUE_BODY="## Security Audit Report\n\n" ISSUE_BODY="${ISSUE_BODY}**Date:** $(date -u +"%Y-%m-%d %H:%M:%S UTC")\n" ISSUE_BODY="${ISSUE_BODY}**Workflow Run:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n\n" if [ -f audit-result.json ]; then # Add vulnerability details ISSUE_BODY="${ISSUE_BODY}### Vulnerabilities Found\n\n" ISSUE_BODY="${ISSUE_BODY}\`\`\`json\n" ISSUE_BODY="${ISSUE_BODY}$(cat audit-result.json)\n" ISSUE_BODY="${ISSUE_BODY}\`\`\`\n\n" fi ISSUE_BODY="${ISSUE_BODY}### Action Required\n\n" ISSUE_BODY="${ISSUE_BODY}1. Review the vulnerability details above\n" ISSUE_BODY="${ISSUE_BODY}2. Update affected packages: \`composer update \`\n" ISSUE_BODY="${ISSUE_BODY}3. Run tests: \`make test\`\n" ISSUE_BODY="${ISSUE_BODY}4. Verify with: \`make security-check\`\n" # Create issue using Gitea API # Note: Requires GITEA_TOKEN secret to be configured if [ -n "${{ secrets.GITEA_TOKEN }}" ]; then curl -X POST \ -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ -H "Content-Type: application/json" \ -d "{\"title\":\"${ISSUE_TITLE}\",\"body\":\"${ISSUE_BODY}\",\"labels\":[\"security\",\"dependencies\",\"automated\"]}" \ "${{ github.server_url }}/api/v1/repos/${{ github.repository }}/issues" else echo "⚠️ GITEA_TOKEN not configured - skipping issue creation" echo "Please add GITEA_TOKEN as repository secret for automated issue creation" fi - name: Notify on failure if: failure() run: | echo "::error::Security vulnerabilities detected! Check the audit results for details." echo "Run 'make security-check' locally to review vulnerabilities."