Update Patterns #554
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Update Patterns | |
| permissions: | |
| contents: write # Commit changes, push updates | |
| statuses: write # Update commit statuses | |
| actions: read # Required for checking out the repository | |
| packages: write # For GitHub Packages (if used) | |
| on: | |
| schedule: | |
| - cron: '0 0 * * *' # Daily at midnight UTC | |
| workflow_dispatch: # Manual trigger | |
| jobs: | |
| update-owasp-waf: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: 🚚 Checkout Repository | |
| uses: actions/checkout@v3 | |
| with: | |
| fetch-depth: 0 # get full git history | |
| - name: ⚙️ Set Up Python 3.11 | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: '3.11' | |
| - name: 📦 Cache pip dependencies | |
| uses: actions/cache@v3 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pip- | |
| - name: 📥 Install Dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements.txt | |
| - name: 🕷️ Run OWASP Scraper | |
| run: python owasp2json.py | |
| - name: 🔄 Convert OWASP to Nginx WAF | |
| run: python json2nginx.py | |
| - name: 🔄 Convert OWASP to Apache WAF | |
| run: python json2apache.py | |
| - name: 🔄 Convert OWASP to Traefik WAF | |
| run: python json2traefik.py | |
| - name: 🔄 Convert OWASP to HAProxy WAF | |
| run: python json2haproxy.py | |
| - name: 🔄 Generate Bad Bot Blockers | |
| run: python badbots.py | |
| - name: 🚀 Commit and Push Changes (if any) | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git add . | |
| # Check if there are any changes *before* committing. | |
| if ! git diff --quiet --exit-code; then | |
| git commit -m "Update WAF rules [$(date +'%Y-%m-%d')]" | |
| git push | |
| else | |
| echo "No changes to commit." | |
| fi | |
| continue-on-error: true # Continue even if no changes | |
| - name: 📦 Create Zip Archives | |
| run: | | |
| mkdir -p dist | |
| (cd waf_patterns/nginx && zip -r ../../dist/nginx_waf.zip .) | |
| (cd waf_patterns/apache && zip -r ../../dist/apache_waf.zip .) | |
| (cd waf_patterns/traefik && zip -r ../../dist/traefik_waf.zip .) | |
| (cd waf_patterns/haproxy && zip -r ../../dist/haproxy_waf.zip .) | |
| - name: 🗑️ Delete Existing 'latest' Tag and Release (if they exist) | |
| run: | | |
| # Delete local tag | |
| git tag -d latest || true | |
| # Delete remote tag (force) | |
| git push --delete origin latest || true | |
| # Delete release, --yes for confirmation | |
| gh release delete latest --yes || true | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: 📝 Generate release notes | |
| if: success() | |
| run: | | |
| set -euo pipefail | |
| BUILD_DATE=$(date -u +'%Y-%m-%d') | |
| # Latest CRS tag (falls back to v4.0 if API is unreachable) | |
| CRS_REF=$(curl -sfL https://api.github.com/repos/coreruleset/coreruleset/releases/latest \ | |
| | jq -r '.tag_name // "v4.0"' 2>/dev/null || echo "v4.0") | |
| # OWASP source coverage | |
| TOTAL_RULES=$(jq length owasp_rules.json) | |
| CATEGORIES=$(jq -r '.[].category' owasp_rules.json | sort -u | wc -l | tr -d ' ') | |
| # Bot pattern counts per backend | |
| NGINX_BOTS=$(grep -c '^\s*"~' waf_patterns/nginx/bots.conf || echo 0) | |
| APACHE_BOTS=$(grep -c '^SecRule REQUEST_HEADERS' waf_patterns/apache/bots.conf || echo 0) | |
| TRAEFIK_BOTS=$(grep -cE '^\s*"' waf_patterns/traefik/bots.toml || echo 0) | |
| HAPROXY_BOTS=$(grep -c '^acl' waf_patterns/haproxy/bots.acl || echo 0) | |
| # Archive sizes (human-readable) | |
| NGINX_SIZE=$(du -h dist/nginx_waf.zip | cut -f1) | |
| APACHE_SIZE=$(du -h dist/apache_waf.zip | cut -f1) | |
| TRAEFIK_SIZE=$(du -h dist/traefik_waf.zip | cut -f1) | |
| HAPROXY_SIZE=$(du -h dist/haproxy_waf.zip | cut -f1) | |
| # SHA-256 checksums | |
| NGINX_SHA=$(sha256sum dist/nginx_waf.zip | cut -d' ' -f1) | |
| APACHE_SHA=$(sha256sum dist/apache_waf.zip | cut -d' ' -f1) | |
| TRAEFIK_SHA=$(sha256sum dist/traefik_waf.zip | cut -d' ' -f1) | |
| HAPROXY_SHA=$(sha256sum dist/haproxy_waf.zip | cut -d' ' -f1) | |
| cat > release_notes.md <<EOF | |
| **Patterns build · ${BUILD_DATE}** | |
| OWASP Core Rule Set [\`coreruleset/coreruleset@${CRS_REF}\`](https://github.com/coreruleset/coreruleset/releases/tag/${CRS_REF}) converted into native WAF rules for four web servers. Generated automatically; no manual edits. | |
| **Coverage:** ${TOTAL_RULES} patterns across ${CATEGORIES} categories — SQLi, XSS, RCE, LFI, RFI, plus generic anomaly and protocol-violation rules. | |
| ### Backends | |
| | Backend | Format | Bots | Archive | Size | | |
| |----------|-------------------|--------:|-----------------------|---------:| | |
| | Nginx | \`map\` + \`if\` | ${NGINX_BOTS} | \`nginx_waf.zip\` | ${NGINX_SIZE} | | |
| | Apache | ModSecurity | ${APACHE_BOTS} | \`apache_waf.zip\` | ${APACHE_SIZE} | | |
| | Traefik | Middleware TOML | ${TRAEFIK_BOTS} | \`traefik_waf.zip\` | ${TRAEFIK_SIZE} | | |
| | HAProxy | ACL | ${HAPROXY_BOTS} | \`haproxy_waf.zip\` | ${HAPROXY_SIZE} | | |
| ### Quick install | |
| \`\`\`bash | |
| curl -LO https://github.com/fabriziosalmi/patterns/releases/latest/download/nginx_waf.zip | |
| unzip nginx_waf.zip -d /etc/nginx/waf_patterns | |
| \`\`\` | |
| Integration guides → [Nginx](https://fabriziosalmi.github.io/patterns/nginx) · [Apache](https://fabriziosalmi.github.io/patterns/apache) · [Traefik](https://fabriziosalmi.github.io/patterns/traefik) · [HAProxy](https://fabriziosalmi.github.io/patterns/haproxy) | |
| ### Verify (SHA-256) | |
| \`\`\`text | |
| ${NGINX_SHA} nginx_waf.zip | |
| ${APACHE_SHA} apache_waf.zip | |
| ${TRAEFIK_SHA} traefik_waf.zip | |
| ${HAPROXY_SHA} haproxy_waf.zip | |
| \`\`\` | |
| \`\`\`bash | |
| echo "${NGINX_SHA} nginx_waf.zip" | sha256sum -c - | |
| \`\`\` | |
| --- | |
| [Documentation](https://fabriziosalmi.github.io/patterns/) · [Source](https://github.com/fabriziosalmi/patterns) · [Issues](https://github.com/fabriziosalmi/patterns/issues) | |
| EOF | |
| echo "Generated release_notes.md ($(wc -l < release_notes.md) lines)" | |
| - name: 🚀 Publish release | |
| if: success() | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: latest | |
| name: WAF rules (Nginx, Apache, Traefik, Haproxy) | |
| body_path: release_notes.md | |
| files: | | |
| dist/nginx_waf.zip | |
| dist/apache_waf.zip | |
| dist/traefik_waf.zip | |
| dist/haproxy_waf.zip | |
| make_latest: 'true' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: 🧹 Clean Up (Optional) | |
| if: always() # Run cleanup even on failure | |
| run: rm -rf ~/.cache/pip | |
| - name: 🚨 Notify on Failure (Optional) | |
| if: failure() | |
| run: | | |
| echo "🚨 Workflow failed! Please investigate." | |
| # Example: Send a Slack notification (requires a Slack webhook URL) | |
| # curl -X POST -H 'Content-type: application/json' --data '{"text":"WAF update workflow failed!"}' ${{ secrets.SLACK_WEBHOOK }} |