diff --git a/.github/workflows/_deploy.yml b/.github/workflows/_deploy.yml
index 0d4afc86420a..35dcd052079e 100644
--- a/.github/workflows/_deploy.yml
+++ b/.github/workflows/_deploy.yml
@@ -17,6 +17,21 @@ on:
description: Name of the built artifact for deployment.
required: true
type: string
+ artifact_run_id:
+ description: ID of the workflow run that uploaded the artifact. Defaults to the current run.
+ required: false
+ type: string
+ default: ''
+ pr_number:
+ description: Number of the pull request to comment on with a link to the preview.
+ required: false
+ type: number
+ default: -1
+ pr_head_sha:
+ description: Commit that the pull request preview was built from.
+ required: false
+ type: string
+ default: ''
s3_prefix:
description: AWS S3 prefix where to store the build.
required: true
@@ -26,8 +41,6 @@ on:
required: true
type: string
-concurrency: deploy-${{ github.ref }}
-
jobs:
deploy-to-cloudfront:
runs-on: ubuntu-latest
@@ -36,13 +49,14 @@ jobs:
deployment: true
url: ${{ inputs.environment_url }}
permissions:
+ actions: read
id-token: write
pull-requests: write
steps:
- name: Create app token
uses: actions/create-github-app-token@v3
id: app-token
- if: ${{ inputs.environment_name == 'preview' }}
+ if: ${{ inputs.pr_number > 0 }}
with:
client-id: ${{ vars.THEOPLAYER_BOT_APP_ID }}
private-key: ${{ secrets.THEOPLAYER_BOT_PRIVATE_KEY }}
@@ -52,6 +66,8 @@ jobs:
with:
name: ${{ inputs.artifact_name }}
path: ${{ github.workspace }}/${{ inputs.artifact_name }}
+ run-id: ${{ inputs.artifact_run_id || github.run_id }}
+ github-token: ${{ github.token }}
- name: Configure AWS credentials βοΈ
uses: aws-actions/configure-aws-credentials@v6
@@ -81,17 +97,18 @@ jobs:
- name: Get deployment timestamp π°οΈ
id: timestamp
- if: ${{ inputs.environment_name == 'preview' }}
+ if: ${{ inputs.pr_number > 0 }}
run: echo "time=$(date -u '+%Y-%m-%d %H:%M %Z')" >> "$GITHUB_OUTPUT"
- name: Add comment to Pull Request with link to preview πΈοΈ
uses: marocchino/sticky-pull-request-comment@v3
- if: ${{ inputs.environment_name == 'preview' }}
+ if: ${{ inputs.pr_number > 0 }}
with:
header: pr-preview
+ number: ${{ inputs.pr_number }}
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
message: |
Documentation preview
:---:
| :rocket: View preview at
${{ inputs.environment_url }}
- |
Deployed from commit ${{ github.event.pull_request.head.sha }} at ${{ steps.timestamp.outputs.time }}.
+ | Deployed from commit ${{ inputs.pr_head_sha }} at ${{ steps.timestamp.outputs.time }}.
diff --git a/.github/workflows/_undeploy.yml b/.github/workflows/_undeploy.yml
index ac17983f2ce0..4cc8f8d8ec4f 100644
--- a/.github/workflows/_undeploy.yml
+++ b/.github/workflows/_undeploy.yml
@@ -15,8 +15,6 @@ on:
required: true
type: string
-concurrency: deploy-${{ github.ref }}
-
jobs:
undeploy-from-cloudfront:
runs-on: ubuntu-latest
diff --git a/.github/workflows/pull-request-preview.yml b/.github/workflows/pull-request-preview.yml
new file mode 100644
index 000000000000..32756727532d
--- /dev/null
+++ b/.github/workflows/pull-request-preview.yml
@@ -0,0 +1,80 @@
+name: 'Pull request preview'
+
+# Deploys the build artifact from "On Pull Requests" to the preview environment.
+# This workflow runs in the context of the main branch, so it has access to
+# secrets and the AWS OIDC token, even for pull requests from forks.
+# It must never check out or run code from the pull request.
+# See https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/
+on:
+ workflow_run:
+ workflows: ['On Pull Requests']
+ types:
+ - completed
+ pull_request_target:
+ types:
+ - closed
+
+jobs:
+ pull-request:
+ name: pull-request
+ if: >-
+ github.event_name == 'workflow_run'
+ && github.event.workflow_run.event == 'pull_request'
+ && github.event.workflow_run.conclusion == 'success'
+ && github.event.workflow_run.actor.login != 'dependabot[bot]'
+ runs-on: ubuntu-latest
+ permissions:
+ pull-requests: read
+ outputs:
+ number: ${{ steps.pr.outputs.number }}
+ head_sha: ${{ github.event.workflow_run.head_sha }}
+ is_fork: ${{ github.event.workflow_run.head_repository.full_name != github.repository }}
+ steps:
+ - name: Find pull request for commit π
+ id: pr
+ # The workflow_run event does not list pull requests from forks,
+ # so look up the open pull request whose head is exactly this commit.
+ run: |
+ number=$(gh api "repos/${GITHUB_REPOSITORY}/commits/${HEAD_SHA}/pulls" \
+ --jq "[.[] | select(.state == \"open\" and .head.sha == \"${HEAD_SHA}\" and .head.repo.full_name == \"${HEAD_REPO}\")] | first | .number")
+ if [[ -z "$number" || "$number" == "null" ]]; then
+ echo "No open pull request found with head ${HEAD_REPO}@${HEAD_SHA}, skipping preview."
+ exit 1
+ fi
+ echo "number=${number}" >> "$GITHUB_OUTPUT"
+ env:
+ GH_TOKEN: ${{ github.token }}
+ HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
+ HEAD_REPO: ${{ github.event.workflow_run.head_repository.full_name }}
+
+ deploy:
+ name: deploy
+ needs: [pull-request]
+ concurrency: preview-pr-${{ needs.pull-request.outputs.number }}
+ uses: ./.github/workflows/_deploy.yml
+ secrets: inherit
+ permissions:
+ actions: read
+ id-token: write
+ pull-requests: write
+ with:
+ # Deployments from forks use a separate environment, so that they can require approval.
+ environment_name: ${{ needs.pull-request.outputs.is_fork == 'true' && 'preview-fork' || 'preview' }}
+ environment_url: '${{ vars.PREVIEW_CLOUDFRONT_URL }}/pr-${{ needs.pull-request.outputs.number }}/'
+ artifact_name: dist.zip
+ artifact_run_id: ${{ github.event.workflow_run.id }}
+ pr_number: ${{ fromJSON(needs.pull-request.outputs.number) }}
+ pr_head_sha: ${{ needs.pull-request.outputs.head_sha }}
+ s3_prefix: 'pr-${{ needs.pull-request.outputs.number }}'
+ cf_invalidate_path: '/pr-${{ needs.pull-request.outputs.number }}*'
+
+ undeploy:
+ name: undeploy
+ if: ${{ github.event_name == 'pull_request_target' && github.triggering_actor != 'dependabot[bot]' }}
+ concurrency: preview-pr-${{ github.event.number }}
+ uses: ./.github/workflows/_undeploy.yml
+ secrets: inherit
+ with:
+ environment_name: preview
+ s3_prefix: 'pr-${{ github.event.number }}'
+ cf_invalidate_path: '/pr-${{ github.event.number }}*'
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index a07dde8d5c21..3a9fa7e4149b 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -1,5 +1,8 @@
name: 'On Pull Requests'
+# This workflow runs on pull requests from forks too, so it has no access to
+# secrets, environment variables or the AWS OIDC token. Deployment happens in
+# pull-request-preview.yml, which never runs code from the pull request.
on:
pull_request:
types:
@@ -7,50 +10,24 @@ on:
- reopened
- synchronize
- ready_for_review
- - closed
jobs:
lint:
name: lint
- if: ${{ github.event.action != 'closed' }}
uses: ./.github/workflows/_lint.yml
secrets: inherit
build:
name: build
- if: ${{ github.event.action != 'closed' }}
uses: ./.github/workflows/_build.yml
with:
environment_name: preview
# Preview URLs look like this: https://[storage-url]/pr-[number]/
- docusaurus_url: ${{ vars.PREVIEW_CLOUDFRONT_URL }}
+ # The URL is hardcoded because `vars` are not available to pull requests from forks.
+ docusaurus_url: 'https://docs-preview.optiview.dolby.com'
docusaurus_base_url: '/pr-${{ github.event.number }}/'
# Prevent PR previews from being indexed by search engines
docusaurus_no_index: 1
# Add an announcement at the top to indicate if this is a preview
docusaurus_pr_number: ${{ github.event.number }}
docusaurus_pr_url: ${{ github.event.pull_request.html_url }}
-
- deploy:
- name: deploy
- needs: [build]
- # Do not run on PRs from Dependabot, since they should not need it.
- if: ${{ github.event.action != 'closed' && github.triggering_actor != 'dependabot[bot]' }}
- uses: ./.github/workflows/_deploy.yml
- secrets: inherit
- with:
- environment_name: preview
- environment_url: '${{ vars.PREVIEW_CLOUDFRONT_URL }}/pr-${{ github.event.number }}/'
- artifact_name: ${{ needs.build.outputs.artifact_name }}
- s3_prefix: 'pr-${{ github.event.number }}'
- cf_invalidate_path: '/pr-${{ github.event.number }}*'
-
- undeploy:
- name: undeploy
- if: ${{ github.event.action == 'closed' && github.triggering_actor != 'dependabot[bot]' }}
- uses: ./.github/workflows/_undeploy.yml
- secrets: inherit
- with:
- environment_name: preview
- s3_prefix: 'pr-${{ github.event.number }}'
- cf_invalidate_path: '/pr-${{ github.event.number }}*'