Problem
The Surge Preview workflow (.github/workflows/surge-preview.yaml) does not work for PRs from forks. This was discovered in PR #243, the first fork PR to trigger the workflow.
GitHub restricts pull_request-triggered workflows from forks in two ways:
- Secrets are not available —
SURGE_LOGIN and SURGE_TOKEN are empty, so the surge deploy silently fails (surge prompts for interactive login instead of deploying, but the step doesn't exit non-zero).
GITHUB_TOKEN is read-only — despite permissions: pull-requests: write in the workflow, the token is downgraded to read for fork PRs, causing the comment step to 403.
This was never caught because all previous PRs were from same-repo branches (opentdf/docs), where secrets and write tokens are available.
Evidence from PR #243 run
Suggested fix
Use the workflow_run pattern to split trusted and untrusted work:
pull_request workflow (untrusted): Build the site and upload the build/ directory as a workflow artifact. This runs in the fork's context — no secrets needed.
workflow_run workflow (trusted): Triggered by completion of the build workflow. Downloads the artifact, deploys to surge (has access to secrets), and posts the preview comment (has write token).
This is the standard approach recommended by GitHub for this scenario. It avoids the security risks of pull_request_target (which would run the fork's code with access to secrets).
Additional improvements to consider
- The surge deploy step should fail loudly when credentials are missing (e.g., check
SURGE_TOKEN is set before running npx surge)
- The teardown job has the same secrets issue for fork PRs, though this is lower priority since teardown runs on PR close
Problem
The Surge Preview workflow (
.github/workflows/surge-preview.yaml) does not work for PRs from forks. This was discovered in PR #243, the first fork PR to trigger the workflow.GitHub restricts
pull_request-triggered workflows from forks in two ways:SURGE_LOGINandSURGE_TOKENare empty, so the surge deploy silently fails (surge prompts for interactive login instead of deploying, but the step doesn't exit non-zero).GITHUB_TOKENis read-only — despitepermissions: pull-requests: writein the workflow, the token is downgraded to read for fork PRs, causing the comment step to 403.This was never caught because all previous PRs were from same-repo branches (
opentdf/docs), where secrets and write tokens are available.Evidence from PR #243 run
SURGE_TOKEN:(empty) andLogin or create surge account by entering email & password.Metadata: read,PullRequests: read(not write)HttpError: Resource not accessible by integration(403)Suggested fix
Use the
workflow_runpattern to split trusted and untrusted work:pull_requestworkflow (untrusted): Build the site and upload thebuild/directory as a workflow artifact. This runs in the fork's context — no secrets needed.workflow_runworkflow (trusted): Triggered by completion of the build workflow. Downloads the artifact, deploys to surge (has access to secrets), and posts the preview comment (has write token).This is the standard approach recommended by GitHub for this scenario. It avoids the security risks of
pull_request_target(which would run the fork's code with access to secrets).Additional improvements to consider
SURGE_TOKENis set before runningnpx surge)