Skip to content

Commit ff745f6

Browse files
rfayclaude
andauthored
build: allow forked PRs to build previews, fixes #79 (#430)
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8a9d455 commit ff745f6

File tree

2 files changed

+598
-0
lines changed

2 files changed

+598
-0
lines changed

.github/FORK_PREVIEW_SETUP.md

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
# Fork Preview Setup Guide
2+
3+
This guide explains how to configure the automated preview generation for forked PRs using Cloudflare Pages.
4+
5+
## Overview
6+
7+
The workflow in `.github/workflows/cloudflare-preview-forks.yml` implements a secure two-stage process:
8+
9+
1. **Build Stage**: Safely builds the site from fork code without exposing secrets
10+
2. **Deploy Stage**: Uses Cloudflare API to deploy the built site with secure credentials
11+
12+
## Required Setup
13+
14+
### 1. Cloudflare Pages Project
15+
16+
The workflow uses a dedicated `ddev-com-fork-previews` Cloudflare Pages project for security isolation from the main site.
17+
18+
**No additional project setup needed** - the project is already configured and the workflow will create stable preview deployments using Cloudflare's Direct Upload API.
19+
20+
### 2. Cloudflare API Token
21+
22+
Create an API token with Pages permissions:
23+
24+
1. Go to [API Tokens](https://dash.cloudflare.com/profile/api-tokens)
25+
2. Click "Create Token"
26+
3. Use "Custom token" template
27+
4. Set permissions:
28+
- `Zone:Zone:Read`
29+
- `Zone:Page Rules:Edit`
30+
- `Account:Cloudflare Pages:Edit`
31+
5. Set account and zone resources as needed
32+
6. Save the token
33+
34+
### 3. Repository Secrets and Variables
35+
36+
Add these in GitHub repository settings → Secrets and variables → Actions:
37+
38+
**Repository Secrets:**
39+
40+
- `TESTS_SERVICE_ACCOUNT_TOKEN`: 1Password service account token (if not already configured)
41+
- Note: `CF_API_TOKEN` is loaded from 1Password `test-secrets` vault, not directly as a repository secret
42+
43+
**Repository Variables:**
44+
45+
- `CF_ACCOUNT_ID`: Your Cloudflare Account ID (found in dashboard sidebar)
46+
- `CF_PAGES_PROJECT`: Set to `ddev-com-fork-previews` (dedicated fork preview project)
47+
48+
### 4. Repository Variables (Optional)
49+
50+
For custom build configurations, set these in GitHub repository settings → Secrets and variables → Actions → Variables:
51+
52+
- `PAGES_BUILD_CMD`: Custom build command (e.g., `npm ci && npm run build`)
53+
- `PAGES_OUTPUT_DIR`: Build output directory (e.g., `dist`, `public`, `build`)
54+
- `PAGES_WORKING_DIR`: Project subdirectory if not root (e.g., `site`, `docs`)
55+
56+
### 5. Enable Workflow
57+
58+
The workflow is triggered automatically for:
59+
60+
- Forked repository PRs only
61+
- Events: `opened`, `synchronize`, `reopened`, `ready_for_review`, `closed`
62+
63+
## Security Features
64+
65+
### Two-Stage Architecture
66+
67+
- **Stage 1 (Build)**: Runs fork code without any secrets
68+
- **Stage 2 (Deploy)**: Uses secrets only after build artifact is created
69+
70+
### Content Validation
71+
72+
- Checks for executable files in content directories
73+
- Validates blog post frontmatter structure
74+
- Detects potentially unsafe content patterns
75+
- Warns about oversized images (>2MB)
76+
- Runs textlint and prettier if available
77+
78+
### Access Controls
79+
80+
- Only processes PRs from forked repositories
81+
- Uses `pull_request_target` with explicit fork checkout
82+
- Separates untrusted code execution from credential access
83+
84+
## Workflow Behavior
85+
86+
### Build Process
87+
88+
1. Detects build system (npm/yarn/pnpm/hugo/custom)
89+
2. Runs content validation and security checks
90+
3. Installs dependencies and runs linting
91+
4. Builds the site
92+
5. Packages output as artifact
93+
94+
### Deployment Process
95+
96+
1. Downloads build artifact from Stage 1
97+
2. Deploys to Cloudflare Pages using API
98+
3. Creates stable preview URL: `https://{hash}.ddev-com-fork-previews.pages.dev`
99+
4. Comments preview URL on the PR
100+
5. Updates comment on subsequent pushes
101+
102+
### PR Lifecycle
103+
104+
- **Opened/Updated**: Creates or updates preview
105+
- **Closed**: Adds closure note (preview remains accessible)
106+
- **Draft**: Still builds and deploys (no special handling)
107+
108+
## Troubleshooting
109+
110+
### Build Failures
111+
112+
- Check build logs in GitHub Actions
113+
- Ensure dependencies install correctly
114+
- Verify build command produces output directory
115+
116+
### Missing Secrets
117+
118+
- Workflow will fail with clear error messages
119+
- Verify all three secrets are set correctly
120+
- Check Cloudflare API token permissions
121+
122+
### Content Validation Errors
123+
124+
- Review security check output
125+
- Fix frontmatter issues in blog posts
126+
- Address linting warnings locally with:
127+
- `ddev npm run textlint:fix`
128+
- `ddev npm run prettier:fix`
129+
130+
### Preview URL Issues
131+
132+
- Verify `ddev-com-fork-previews` Cloudflare Pages project exists and is accessible
133+
- Check account ID matches the project's organization
134+
- Ensure `CF_PAGES_PROJECT` is set to `ddev-com-fork-previews`
135+
136+
## Manual Testing
137+
138+
To test the workflow:
139+
140+
1. Create a test fork of the repository
141+
2. Make a content change (e.g., add a blog post)
142+
3. Open a PR from the fork
143+
4. Watch GitHub Actions for build/deploy progress
144+
5. Check for preview URL comment on the PR
145+
146+
## Maintenance
147+
148+
### Regular Tasks
149+
150+
- Monitor Cloudflare Pages usage and costs
151+
- Review security warnings in build logs
152+
- Update dependencies in fork validation steps
153+
- Clean up old preview deployments if needed
154+
155+
### Updates
156+
157+
- Keep `cloudflare/pages-action` version current
158+
- Monitor Cloudflare API changes
159+
- Update content validation rules as needed
160+
161+
## Known Issues & Future Improvements
162+
163+
### URL Stability Problem
164+
165+
Currently, Cloudflare's Direct Upload API creates a new deployment hash with each push, resulting in changing preview URLs like:
166+
167+
- First push: `https://2e1a74f4.ddev-com-fork-previews.pages.dev`
168+
- Second push: `https://e98fa6ff.ddev-com-fork-previews.pages.dev`
169+
170+
This breaks the ability to bookmark or share stable preview URLs for review purposes.
171+
172+
**Potential Solutions to Investigate:**
173+
174+
1. **Force predictable branch naming**: Try using branch names like `pr${{ github.event.pull_request.number }}` and construct expected URLs manually
175+
2. **Track and reuse first URL**: Store the initial deployment URL and attempt to update the same deployment rather than creating new ones
176+
3. **Use Cloudflare API directly**: Bypass the GitHub action and use Wrangler CLI or direct API calls for more control over deployment naming
177+
178+
**Current Status**: Comment updating works correctly (single comment per PR), but URLs change with each deployment. This is the main remaining issue to solve for optimal user experience.

0 commit comments

Comments
 (0)