### Summary
Adds a new CI workflow that automatically synchronizes
`ee/maintained-apps/outputs` directory contents to a Cloudflare R2
bucket. This enables serving maintained apps output files via CDN with
minimal operational overhead.
### What It Does
- **Automatic sync on changes**: Triggers whenever files in
`ee/maintained-apps/outputs/**` are committed to main
- **Manual trigger support**: Can be run on-demand via Actions UI with
optional dry-run mode
- **Idempotent operations**: Uses `aws s3 sync --delete` to keep bucket
in sync with source
- **Failure notifications**: Posts to Slack (#help-p1) if sync fails
### Key Features
| Feature | Description |
|---------|-------------|
| **Dry-run mode** | Preview what would be synced without uploading (via
workflow_dispatch input) |
| **Concurrency control** | Cancels in-progress runs on same branch to
avoid conflicts |
| **Retry logic** | 10 retry attempts with standard AWS retry mode for
transient failures |
| **Security hardening** | Uses `step-security/harden-runner` for egress
policy enforcement |
### Configuration Status ✅
All required configuration is already in place:
- ✅ R2 bucket `maintained-apps` exists
- ✅ Secret `R2_MAINTAINED_APPS_ACCESS_KEY_ID` configured
- ✅ Secret `R2_MAINTAINED_APPS_ACCESS_KEY_SECRET` configured
- ✅ Secret `R2_ENDPOINT` configured
- ✅ Slack webhook secret `SLACK_G_HELP_P1_WEBHOOK_URL` available
### Validation
- ✅ **actionlint**: Passed with no errors or warnings
- ✅ **YAML syntax**: Validated
### Testing
To verify after merging:
1. Trigger manually via Actions → "Sync Maintained Apps Outputs to R2" →
Run workflow
2. Use dry-run mode first to preview what would be synced without
uploading
### Notes
- Uses AWS CLI (pre-installed on ubuntu-latest) with R2-compatible
endpoint
- Minimal permissions model - only `contents: read` required
- bucket available at https://maintained-apps.fleetdm.com/