Skip to content
Closed
Show file tree
Hide file tree
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
64 changes: 54 additions & 10 deletions .github/workflows/remote-docs-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ on:
description: Open pull request to preview
required: true
type: string
approved_head_sha:
description: Exact pull request head SHA approved by the dispatching workflow
required: false
default: ""
type: string
workflow_call:
inputs:
remote_name:
Expand All @@ -31,6 +36,11 @@ on:
description: Repository containing the pull request
required: true
type: string
approved_head_sha:
description: Exact pull request head SHA approved by the dispatching workflow
required: false
default: ""
type: string
secrets:
WORKFLOW_AUTH_PUBLIC_APP_ID:
required: true
Expand Down Expand Up @@ -79,15 +89,15 @@ jobs:
fi

- name: Check out the trusted documentation site
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
with:
repository: ClickHouse/mintlify-docs-dev
ref: main
path: site
persist-credentials: false

- name: Set up Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 24

Expand All @@ -112,21 +122,34 @@ jobs:
fi
echo "sha=$site_sha" >> "$GITHUB_OUTPUT"

- name: Resolve the source repository
id: source
env:
SOURCE_REPOSITORY: ${{ inputs.source_repository }}
run: |
if [[ ! "$SOURCE_REPOSITORY" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then
echo "Source repository must use the owner/name form." >&2
exit 1
fi
echo "owner=${SOURCE_REPOSITORY%%/*}" >> "$GITHUB_OUTPUT"
echo "name=${SOURCE_REPOSITORY#*/}" >> "$GITHUB_OUTPUT"

- name: Mint a source-repository token
id: source-token
uses: actions/create-github-app-token@v3
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.WORKFLOW_AUTH_PUBLIC_APP_ID }}
private-key: ${{ secrets.WORKFLOW_AUTH_PUBLIC_PRIVATE_KEY }}
owner: ClickHouse
repositories: ${{ inputs.source_repository }}
owner: ${{ steps.source.outputs.owner }}
repositories: ${{ steps.source.outputs.name }}
permission-contents: read
permission-pull-requests: read
permission-pull-requests: write

- name: Resolve the pull request head
id: pull-request
env:
GH_TOKEN: ${{ steps.source-token.outputs.token }}
APPROVED_HEAD_SHA: ${{ inputs.approved_head_sha }}
PULL_REQUEST_NUMBER: ${{ inputs.pull_request_number }}
SOURCE_REPOSITORY: ${{ inputs.source_repository }}
run: |
Expand All @@ -142,6 +165,16 @@ jobs:
echo "GitHub returned an invalid pull request head SHA." >&2
exit 1
fi
if [[ -n "$APPROVED_HEAD_SHA" ]]; then
if [[ ! "$APPROVED_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]]; then
echo "The dispatching workflow supplied an invalid approved head SHA." >&2
exit 1
fi
if [[ "$head_sha" != "$APPROVED_HEAD_SHA" ]]; then
echo "Pull request head changed after preview approval: expected $APPROVED_HEAD_SHA, found $head_sha." >&2
exit 1
fi
fi
if [[ ! "$head_repository" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then
echo "GitHub returned an invalid pull request head repository." >&2
exit 1
Expand Down Expand Up @@ -402,14 +435,25 @@ jobs:
deployment_finished=true

- name: Add the preview link to the pull request
if: github.repository == inputs.source_repository
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ steps.source-token.outputs.token }}
GH_REPO: ${{ inputs.source_repository }}
PREVIEW_URL: ${{ steps.deploy.outputs.preview_url }}
PULL_REQUEST_NUMBER: ${{ inputs.pull_request_number }}
run: |
gh pr comment "$PULL_REQUEST_NUMBER" --body "Documentation preview: $PREVIEW_URL"
marker="<!-- nimbus-remote-docs-preview -->"
docs_url="${PREVIEW_URL%/}/docs"
body="$(printf '%s\n\nDocumentation preview: %s' "$marker" "$docs_url")"
comment_id="$(
gh api --paginate "repos/$GH_REPO/issues/$PULL_REQUEST_NUMBER/comments" \
--jq ".[] | select(.body | contains(\"$marker\")) | .id" \
| tail -n 1
)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sticky comment matches any author

Medium Severity

The new sticky preview lookup takes the last pull request comment whose body contains the nimbus-remote-docs-preview marker and does not check who wrote it. A later quote-reply or any comment that repeats that marker can be patched instead of the workflow's own comment, which overwrites a human note or leaves the official preview link stale.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 652cbf8. Configure here.

if [[ -n "$comment_id" ]]; then
gh api --method PATCH "repos/$GH_REPO/issues/comments/$comment_id" -f body="$body" >/dev/null
else
gh pr comment "$PULL_REQUEST_NUMBER" --body "$body"
fi

- name: Show the directly requested preview
if: github.repository != inputs.source_repository
Expand Down
6 changes: 1 addition & 5 deletions reports/templates/airgap-docs-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,10 @@ permissions:

jobs:
preview:
uses: ClickHouse/mintlify-docs-dev/.github/workflows/remote-docs-preview.yml@main
uses: ClickHouse/integrations-shared-workflows/.github/workflows/remote-docs-preview.yml@main
with:
remote_name: clickhouse-private
pull_request_number: ${{ fromJSON(inputs.pull_request_number) }}
source_repository: ${{ github.repository }}
secrets:
WORKFLOW_AUTH_PUBLIC_APP_ID: ${{ secrets.WORKFLOW_AUTH_PUBLIC_APP_ID }}
WORKFLOW_AUTH_PUBLIC_PRIVATE_KEY: ${{ secrets.WORKFLOW_AUTH_PUBLIC_PRIVATE_KEY }}
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
30 changes: 17 additions & 13 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,15 @@ Production source topology lives only in `remotes.json`; production fetches each
registered repository from `main`. Remote CI supplies the registered name,
repository, and exceptional immutable SHA only when requesting a preview.

Remote repositories create previews through
`.github/workflows/remote-docs-preview.yml`. The caller invokes the reusable
workflow manually with a pull request number. It uses a repository-scoped
GitHub App token only to resolve the immutable head SHA and the branch or fork
repository that owns it, then asks Vercel to build trusted Nimbus `main` in the
`connect-preview` environment. The Vercel build uses
Remote repositories create previews through the reusable
`ClickHouse/integrations-shared-workflows/.github/workflows/remote-docs-preview.yml`
dispatcher. The caller invokes it manually with a pull request number. The
shared workflow resolves the immutable head SHA, then uses a repository-scoped
GitHub App token to dispatch `.github/workflows/remote-docs-preview.yml` in this
repository. Vercel credentials remain available only to this central workflow,
which verifies that the approved SHA is still the pull request head before it
asks Vercel to build trusted Nimbus `main` in the `connect-preview` environment.
The Vercel build uses
its OIDC identity to request a short-lived, `contents:read` token from Vercel
Connect for the branch or fork repository. Public repositories are fetched
anonymously. `bin/fetch-remotes.ts` exits before
Expand All @@ -78,13 +81,14 @@ project's Git connection and updates one preview comment on the pull request.
Both primary-repository branches and forks use standard Preview and omit every
registered remote source.

Source-repository pull requests use
`.github/workflows/remote-docs-preview.yml`. Vercel builds trusted Nimbus
`main`, selects exactly one registered source with `DOCS_REMOTE_*`, and fetches
the pull request's immutable head revision. Trusted branches and forks have the
same source-only build scope. They use `connect-preview` so private registered
sources can obtain a short-lived token; public sources remain anonymously
fetchable.
Source-repository pull requests use the shared dispatcher described above. The
central `.github/workflows/remote-docs-preview.yml` workflow builds trusted
Nimbus `main`, selects exactly one registered source with `DOCS_REMOTE_*`, and
fetches the pull request's immutable head revision. Trusted branches and forks
have the same source-only build scope. They use `connect-preview` so private
registered sources can obtain a short-lived token; public sources remain
anonymously fetchable. The central workflow posts the completed preview URL
back to the source pull request with a short-lived GitHub App token.

After a source-repository change reaches its trusted production branch, that
repository calls `.github/workflows/site-production.yml`. The reusable workflow
Expand Down