LibreChat/.github/workflows/gitnexus-pr-command.yml
Danny Avila 21574f02ca
🛡️ chore: Harden CI Supply Chain Workflows (#13090)
* chore: harden CI supply chain workflows

* chore: address CI hardening review feedback

* chore: tighten GitNexus dispatch hardening

* chore: use app token for Locize PR automation

* chore: use dedicated token for Locize PR automation
2026-05-18 16:55:25 -04:00

141 lines
5.7 KiB
YAML

# Responds to `/gitnexus index` comments on pull requests.
#
# Gated to the same author_association roles (OWNER, MEMBER, COLLABORATOR)
# as the automatic PR index trigger, but applied to the COMMENTER, not
# the PR author. This intentionally lets a contributor index a PR from
# a non-contributor / first-time fork author — the contributor takes
# responsibility for the trust boundary by typing the command.
#
# When a matching comment lands on a PR, this workflow dispatches
# `gitnexus-index.yml` with the PR number and the `refs/pull/<N>/head`
# ref so indexing works for fork PRs too (GitHub mirrors every PR's
# head ref into the base repo regardless of which fork it originated
# from, so actions/checkout can always resolve it).
#
# Use cases:
# - Re-index a PR after a rebase without pushing a new commit
# - Index a docs-only PR that was skipped by paths-ignore
# - Index a non-contributor (fork) PR that the auto-trigger skipped
# - Re-run a failed index
#
# Supported commands:
# /gitnexus index — index the PR with embeddings (default)
# /gitnexus index embeddings — explicit form of the above; same effect
# /gitnexus index fast — graph-only index (skip embeddings), for
# a quick re-index without waiting ~5 min
# of embedding generation
name: GitNexus PR Command
on:
issue_comment:
types: [created]
permissions:
contents: read
pull-requests: write
actions: write # needed to dispatch gitnexus-index.yml
concurrency:
group: gitnexus-pr-command-${{ github.event.issue.number }}
cancel-in-progress: false
jobs:
dispatch:
# Only run for PR comments that start with /gitnexus from trusted
# commenters. Intentionally checks the COMMENTER's association so a
# contributor can index a non-contributor's PR on demand.
if: |
github.event.issue.pull_request != null &&
startsWith(github.event.comment.body, '/gitnexus') &&
(github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'COLLABORATOR')
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Parse command and resolve PR head ref
id: parse
uses: actions/github-script@v7
with:
script: |
const body = context.payload.comment.body.trim();
const match = body.match(/^\/gitnexus\s+(\w+)(?:\s+(\w+))?/);
if (!match) {
core.setFailed(`Unrecognized command: ${body}. Try: /gitnexus index [fast]`);
return;
}
const [, subcommand, modifier] = match;
if (subcommand !== 'index') {
core.setFailed(`Unknown subcommand: ${subcommand}. Only 'index' is supported.`);
return;
}
// Default to embeddings on — a contributor typing the command
// has already decided they want a full re-index. The `fast`
// modifier is the explicit opt-out for graph-only runs.
// `embeddings` is accepted as a no-op alias for backwards
// compat with the previous command form.
let embeddings = 'true';
if (modifier === 'fast' || modifier === 'graph-only' || modifier === 'no-embeddings') {
embeddings = 'false';
}
// Use refs/pull/<N>/head instead of the raw head SHA. GitHub
// mirrors every PR's head into the base repo as this ref, so
// actions/checkout can always resolve it — even for PRs from
// forks whose raw SHAs don't exist in the base repo.
const prNum = context.payload.issue.number;
core.setOutput('pr_number', String(prNum));
core.setOutput('pr_ref', `refs/pull/${prNum}/head`);
core.setOutput('embeddings', embeddings);
core.info(
`Dispatching index for PR #${prNum} at refs/pull/${prNum}/head (embeddings=${embeddings}, modifier=${modifier || '(none)'})`,
);
- name: Dispatch gitnexus-index workflow
uses: actions/github-script@v7
env:
EMBEDDINGS: ${{ steps.parse.outputs.embeddings }}
PR_NUMBER: ${{ steps.parse.outputs.pr_number }}
PR_REF: ${{ steps.parse.outputs.pr_ref }}
with:
script: |
const prNumber = process.env.PR_NUMBER || '';
const prRef = process.env.PR_REF || '';
const embeddings = process.env.EMBEDDINGS || 'false';
if (!/^[0-9]+$/.test(prNumber)) {
core.setFailed(`Invalid PR number: ${prNumber}`);
return;
}
if (prRef !== `refs/pull/${prNumber}/head`) {
core.setFailed(`Invalid PR ref: ${prRef}`);
return;
}
if (!['true', 'false'].includes(embeddings)) {
core.setFailed(`Invalid embeddings value: ${embeddings}`);
return;
}
await github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'gitnexus-index.yml',
ref: 'main',
inputs: {
pr_number: prNumber,
pr_ref: prRef,
embeddings,
force: 'false',
deploy_after: 'true',
},
});
- name: React to the comment
uses: actions/github-script@v7
with:
script: |
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: 'rocket',
});