Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions .github/workflows/pr-docs-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
name: Deploy PR Docs Preview

on:
pull_request:
types: [opened, synchronize, reopened, closed]

permissions:
contents: write
pull-requests: write

concurrency:
group: pr-docs-preview-${{ github.event.number }}
cancel-in-progress: true

jobs:
deploy-preview:
if: github.event.action != 'closed'
runs-on: ubuntu-latest
steps:
- name: Check out
uses: actions/checkout@v4

- name: Check out gh-pages
uses: actions/checkout@v4
with:
ref: gh-pages
path: gh-pages-deploy

- name: Set up the environment
uses: ./.github/actions/setup-python-env

- name: Install Pandoc
run: |
sudo apt-get update
sudo apt-get install -y pandoc

- name: Determine latest version
id: version
run: |
VERSION=$(uv run python -c "from scripts.config import LATEST_VERSION; print(LATEST_VERSION)")
SHORT=$(uv run python -c "from scripts.config import LATEST_VERSION, version_to_short; print(version_to_short(LATEST_VERSION))")
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "version_short=${SHORT}" >> "$GITHUB_OUTPUT"

- name: Clone EnergyPlus source (sparse, doc/ only)
run: |
mkdir -p build/sources
git clone --filter=blob:none --no-checkout --depth=1 \
--branch ${{ steps.version.outputs.version }} --single-branch \
https://github.com/NatLabRockies/EnergyPlus.git \
build/sources/${{ steps.version.outputs.version }}
git -C build/sources/${{ steps.version.outputs.version }} sparse-checkout set doc
git -C build/sources/${{ steps.version.outputs.version }} checkout

- name: Convert docs
run: |
uv run python -m scripts.convert \
--source build/sources/${{ steps.version.outputs.version }} \
--output build/${{ steps.version.outputs.version_short }} \
--version ${{ steps.version.outputs.version }} \
--verbose

- name: Deploy preview to gh-pages
run: |
rm -rf "gh-pages-deploy/pr-preview/pr-${{ github.event.number }}"
mkdir -p "gh-pages-deploy/pr-preview/pr-${{ github.event.number }}"
cp -r build/${{ steps.version.outputs.version_short }}/site/. "gh-pages-deploy/pr-preview/pr-${{ github.event.number }}/"
cd gh-pages-deploy
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add -A
git diff --cached --quiet || {
git commit -m "Deploy docs preview for PR #${{ github.event.number }}"
git pull --rebase origin gh-pages
git push origin gh-pages
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Gate gh-pages pushes for fork pull requests

This workflow is triggered for all pull_request events and always attempts to push to gh-pages, but forked PRs run with a read-only workflow token, so the deploy path fails even when conversion succeeds. That means external contributors (the main OSS contribution path) will consistently get a failing preview job and no preview URL. Add a fork check to skip write operations (or move to a safe pull_request_target pattern) so fork PRs do not hard-fail.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codex what is a safe pull_request_target pattern?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Safe pull_request_target pattern (answer to your question)

If you do choose pull_request_target, the safe pattern is:

  1. Run only trusted/privileged actions there (labeling, commenting, dispatching, metadata checks).
  2. Do not run untrusted PR code directly in that context (no checkout of PR head + build using secrets/write token).
  3. Split workflows: untrusted build/test on pull_request; privileged publish/comment on pull_request_target (or via workflow_run) with strict conditions/allowlists.

For this PR, I implemented the safer immediate fix requested by review: fork-aware write gating on pull_request, which prevents hard-failures for external contributors while preserving behavior for same-repo PRs. .github/workflows/pr-docs-preview.ymlL17-L25 .github/workflows/pr-docs-preview.ymlL64-L83

Testing

  • ruby -e "require 'yaml'; YAML.load_file('.github/workflows/pr-docs-preview.yml'); puts 'YAML OK'"
  • ⚠️ python - <<'PY'\nimport yaml,sys\nwith open('.github/workflows/pr-docs-preview.yml') as f:\n yaml.safe_load(f)\nprint('YAML OK')\nPY (warning: PyYAML is not installed in the environment)
  • curl -Ls https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows | rg -n "pull_request_target|Warning|security" | head -n 20

Committed and opened a follow-up PR via the required PR tool.

View task →

}

- name: Add or update preview comment
uses: actions/github-script@v7
with:
script: |
const previewUrl = `https://docs.idfkit.com/pr-preview/pr-${context.issue.number}/`;
const marker = '<!-- docs-preview-comment -->';
const body = [
marker,
`**Docs preview** for this PR is available at:`,
previewUrl,
].join('\n');

const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existing = comments.find(c => c.body.includes(marker));

if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}

cleanup-preview:
if: github.event.action == 'closed'
runs-on: ubuntu-latest
steps:
- name: Check out gh-pages branch
uses: actions/checkout@v4
with:
ref: gh-pages

- name: Remove preview directory
run: |
if [ -d "pr-preview/pr-${{ github.event.number }}" ]; then
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git rm -rf "pr-preview/pr-${{ github.event.number }}"
git commit -m "Remove docs preview for PR #${{ github.event.number }}"
git pull --rebase origin gh-pages
git push origin gh-pages
fi