Skip to content

fix(ci): Add Cloudflare cache purging to rules deployment workflow#533

Merged
shivasurya merged 2 commits intomainfrom
fix/cloudflare-cache-purge
Feb 16, 2026
Merged

fix(ci): Add Cloudflare cache purging to rules deployment workflow#533
shivasurya merged 2 commits intomainfrom
fix/cloudflare-cache-purge

Conversation

@shivasurya
Copy link
Owner

Problem

After deploying updated rule bundles to R2, Cloudflare serves cached versions for up to 24 hours, causing checksum verification failures:

Error: checksum mismatch: expected eb37afa9..., got eef87ec7...

Root Cause

ZIP files are uploaded with cache headers:

cache-control: max-age=86400, immutable, public  # 24 hour cache

When new ZIPs are deployed (e.g., after deterministic ZIP fix in #532), Cloudflare edge locations continue serving old cached versions until TTL expires, even though the new files exist on origin.

Verification

Confirmed cache issue by bypassing cache with query parameters:

# Without cache-buster (OLD cached file)
$ curl -s https://assets.codepathfinder.dev/rules/python/deserialization.zip | sha256sum
eef87ec74cd2772aa5a62f64df38026afdfbd84debc4e342590beb109a8a90e4

# With cache-buster (NEW file from origin)
$ curl -s "https://assets.codepathfinder.dev/rules/python/deserialization.zip?nocache=1" | sha256sum
eb37afa960dadb50469a5ad55a75ff7b60e8a156d37809299a4f659326d7a46d ← Correct!

Solution

Added automatic Cloudflare cache purging after successful R2 upload:

  1. Collects all ZIP URLs from dist/rules directory
  2. Calls Cloudflare Purge API to invalidate cached files
  3. Gracefully handles missing credentials (logs warning, non-blocking)
  4. Provides clear feedback on purge success/failure

Implementation

New workflow step:

- name: Purge Cloudflare cache
  env:
    CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }}
    CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
  run: |
    # Builds JSON array of file URLs
    # Calls: POST /zones/{zone_id}/purge_cache
    # Purges all uploaded ZIP files

API Call:

curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"files":["https://assets.codepathfinder.dev/rules/python/deserialization.zip", ...]}'

Configuration Required

Add these GitHub Secrets to enable cache purging:

  1. CLOUDFLARE_ZONE_ID: Zone ID for codepathfinder.dev
  2. CLOUDFLARE_API_TOKEN: API token with "Cache Purge" permission

To create API token:

  • Cloudflare Dashboard → My Profile → API Tokens
  • Create Token → Custom Token
  • Permissions: Zone → Cache Purge → Purge
  • Zone Resources: Include → Specific zone → codepathfinder.dev

Behavior

With credentials configured:

🔄 Purging Cloudflare cache for updated rule bundles...
✅ Cache purged successfully for all rule bundles

Without credentials (graceful degradation):

⚠️  Cloudflare credentials not configured - skipping cache purge
Add CLOUDFLARE_ZONE_ID and CLOUDFLARE_API_TOKEN secrets to enable automatic cache purging
Files will be available after cache expires (24h)

Files Changed

File Changes Description
.github/workflows/deploy-rules.yml +47 lines Add Cloudflare cache purge step

Impact

  • ✓ Immediate availability: New rules accessible within seconds of deployment
  • ✓ No more checksum errors: Users get latest files immediately
  • ✓ Non-blocking: Missing credentials don't break deployment
  • ✓ Backward compatible: Works with or without secrets

Dependencies

Testing

Once secrets are configured, test by:

  1. Triggering manual workflow run
  2. Checking logs for "✅ Cache purged successfully"
  3. Verifying immediate file availability (no 24h wait)

Notes

  • Non-blocking: Deployment succeeds even if cache purge fails
  • Graceful degradation: Works without secrets (just logs warning)
  • Future-proof: Automatically purges all ZIP files in dist/rules

## Problem
After deploying updated rule bundles to R2, Cloudflare serves cached
versions for up to 24 hours, causing checksum verification failures:

```
Error: checksum mismatch: expected eb37afa9..., got eef87ec7...
```

## Root Cause
ZIP files are uploaded with cache headers:
```
cache-control: max-age=86400, immutable, public  # 24 hour cache
```

When new ZIPs are deployed (e.g., after deterministic ZIP fix in #532),
Cloudflare edge locations continue serving old cached versions until TTL
expires, even though the new files exist on origin.

## Verification
Confirmed cache issue by bypassing cache with query parameters:
```bash
# Without cache-buster (OLD cached file)
$ curl -s https://assets.codepathfinder.dev/rules/python/deserialization.zip | sha256sum
eef87ec74cd2772aa5a62f64df38026afdfbd84debc4e342590beb109a8a90e4

# With cache-buster (NEW file from origin)
$ curl -s "https://assets.codepathfinder.dev/rules/python/deserialization.zip?nocache=1" | sha256sum
eb37afa960dadb50469a5ad55a75ff7b60e8a156d37809299a4f659326d7a46d ← Correct!
```

## Solution
Added automatic Cloudflare cache purging after successful R2 upload:

1. **Collects all ZIP URLs** from dist/rules directory
2. **Calls Cloudflare Purge API** to invalidate cached files
3. **Gracefully handles missing credentials** (logs warning, non-blocking)
4. **Provides clear feedback** on purge success/failure

## Implementation

**New workflow step:**
```yaml
- name: Purge Cloudflare cache
  env:
    CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }}
    CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
  run: |
    # Builds JSON array of file URLs
    # Calls: POST /zones/{zone_id}/purge_cache
    # Purges all uploaded ZIP files
```

**API Call:**
```bash
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"files":["https://assets.codepathfinder.dev/rules/python/deserialization.zip", ...]}'
```

## Configuration Required

Add these GitHub Secrets to enable cache purging:
1. **CLOUDFLARE_ZONE_ID**: Zone ID for codepathfinder.dev
2. **CLOUDFLARE_API_TOKEN**: API token with "Cache Purge" permission

**To create API token:**
- Cloudflare Dashboard → My Profile → API Tokens
- Create Token → Custom Token
- Permissions: Zone → Cache Purge → Purge
- Zone Resources: Include → Specific zone → codepathfinder.dev

## Behavior

**With credentials configured:**
```
🔄 Purging Cloudflare cache for updated rule bundles...
✅ Cache purged successfully for all rule bundles
```

**Without credentials (graceful degradation):**
```
⚠️  Cloudflare credentials not configured - skipping cache purge
Add CLOUDFLARE_ZONE_ID and CLOUDFLARE_API_TOKEN secrets to enable automatic cache purging
Files will be available after cache expires (24h)
```

## Files Changed
| File | Changes | Description |
|------|---------|-------------|
| `.github/workflows/deploy-rules.yml` | +47 lines | Add Cloudflare cache purge step |

## Impact
- **✓ Immediate availability**: New rules accessible within seconds of deployment
- **✓ No more checksum errors**: Users get latest files immediately
- **✓ Non-blocking**: Missing credentials don't break deployment
- **✓ Backward compatible**: Works with or without secrets

## Dependencies
- **← PR #532**: Deterministic ZIP creation (already merged)
- **Requires**: GitHub Secrets configuration (CLOUDFLARE_ZONE_ID, CLOUDFLARE_API_TOKEN)

## Testing
Once secrets are configured, test by:
1. Triggering manual workflow run
2. Checking logs for "✅ Cache purged successfully"
3. Verifying immediate file availability (no 24h wait)
@safedep
Copy link

safedep bot commented Feb 16, 2026

SafeDep Report Summary

Green Malicious Packages Badge Green Vulnerable Packages Badge Green Risky License Badge

No dependency changes detected. Nothing to scan.

This report is generated by SafeDep Github App

@github-actions
Copy link

Code Pathfinder Security Scan

Pass Critical High Medium Low Info

No security issues detected.

Metric Value
Files Scanned 1
Rules 38

Powered by Code Pathfinder

@shivasurya shivasurya self-assigned this Feb 16, 2026
@shivasurya shivasurya added bug Something isn't working github_actions Pull requests that update GitHub Actions code chore labels Feb 16, 2026
- Don't print full API response (may contain sensitive data)
- Write response to temp file instead of printing
- Only show HTTP status code on failure
- Count files purged instead of listing all URLs
- Clean up temp response file after use

This prevents potential exposure of:
- Cloudflare zone details
- API response metadata
- Error messages with internal details
@shivasurya shivasurya merged commit b3dad5b into main Feb 16, 2026
5 checks passed
@shivasurya shivasurya deleted the fix/cloudflare-cache-purge branch February 16, 2026 02:12
@codecov
Copy link

codecov bot commented Feb 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.74%. Comparing base (07e873b) to head (5d96e89).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #533   +/-   ##
=======================================
  Coverage   82.74%   82.74%           
=======================================
  Files         133      133           
  Lines       15666    15666           
=======================================
  Hits        12963    12963           
  Misses       2222     2222           
  Partials      481      481           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working chore github_actions Pull requests that update GitHub Actions code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant