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
190 changes: 190 additions & 0 deletions .github/workflows/nvidia-nim-pr-maintenance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
name: NVIDIA NIM PR Maintenance

on:
workflow_call:
inputs:
target_repository:
description: Repository to scan in owner/name form
required: false
default: ""
type: string
base_branch:
description: Base branch to scan; defaults to the caller repository default branch
required: false
default: ""
type: string
dry_run:
description: Print actions without dispatching an autofix
required: false
default: false
type: boolean
max_prs:
description: Maximum open pull requests to inspect
required: false
default: "50"
type: string
max_dispatches:
description: Maximum NVIDIA NIM autofix runs to dispatch
required: false
default: "1"
type: string
retry_hours:
description: Minimum hours before redispatching the same head
required: false
default: "1"
type: string
secrets:
PR_REVIEW_MERGE_TOKEN:
description: Optional cross-repository GitHub write token
required: false
OPENCODE_APPROVE_TOKEN:
description: Optional existing OpenCode GitHub write token fallback
required: false
repository_dispatch:
types: [nvidia-nim-pr-maintenance]
schedule:
- cron: "23 * * * *"

concurrency:
group: >-
nvidia-nim-pr-maintenance-${{
github.event.client_payload.target_repository || inputs.target_repository ||
vars.PR_REVIEW_FIX_TARGET_REPOSITORY || github.repository }}
cancel-in-progress: true

permissions:
contents: read

jobs:
dispatch-review-fixes:
runs-on: ubuntu-24.04
permissions:
actions: write
contents: read
id-token: write
issues: write
pull-requests: read
statuses: read
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
TARGET_REPOSITORY: >-
${{ github.event.client_payload.target_repository || inputs.target_repository ||
vars.PR_REVIEW_FIX_TARGET_REPOSITORY || github.repository }}
DEFAULT_BRANCH: >-
${{ github.event.client_payload.base_branch || inputs.base_branch ||
vars.PR_REVIEW_FIX_BASE_BRANCH || github.event.repository.default_branch }}
DRY_RUN: >-
${{ github.event.client_payload.dry_run == true ||
github.event.client_payload.dry_run == 'true' || inputs.dry_run == true }}
MAX_PRS: ${{ github.event.client_payload.max_prs || inputs.max_prs || '50' }}
MAX_DISPATCHES: >-
${{ github.event.client_payload.max_dispatches || inputs.max_dispatches || '1' }}
RETRY_HOURS: ${{ github.event.client_payload.retry_hours || inputs.retry_hours || '1' }}
AUTOFIX_REPOSITORY: ContextualWisdomLab/.github
AUTOFIX_WORKFLOW: nvidia-nim-pr-review-autofix.yml
steps:
- name: Resolve immutable called-workflow source
id: trusted_source
env:
OIDC_AUDIENCE: cwl-nvidia-nim-pr-maintenance-source
run: |
set -euo pipefail
request_url="${ACTIONS_ID_TOKEN_REQUEST_URL}"
separator="&"
case "$request_url" in
*\?*) ;;
*) separator="?" ;;
esac
response="$(
curl -fsS \
-H "Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \
"${request_url}${separator}audience=${OIDC_AUDIENCE}"
)"
token="$(jq -r '.value // empty' <<<"$response")"
[ -n "$token" ] || { echo "::error::OIDC token response was empty."; exit 1; }
payload_segment="$(cut -d. -f2 <<<"$token")"
case $((${#payload_segment} % 4)) in
2) payload_segment="${payload_segment}==" ;;
3) payload_segment="${payload_segment}=" ;;
esac
payload="$(printf '%s' "$payload_segment" | tr '_-' '/+' | base64 -d)"
source_sha="$(jq -r '.job_workflow_sha // .workflow_sha // empty' <<<"$payload")"
source_ref="$(jq -r '.job_workflow_ref // .workflow_ref // empty' <<<"$payload")"
if ! [[ "$source_sha" =~ ^[0-9a-fA-F]{40}$ ]]; then
echo "::error::Called workflow source did not resolve to an immutable SHA."
exit 1
fi
case "$source_ref" in
ContextualWisdomLab/.github/.github/workflows/nvidia-nim-pr-maintenance.yml@*) ;;
*) echo "::error::Unexpected called workflow source: ${source_ref:-missing}."; exit 1 ;;
esac
echo "sha=$source_sha" >>"$GITHUB_OUTPUT"

- name: Checkout immutable scheduler source
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: ContextualWisdomLab/.github
ref: ${{ steps.trusted_source.outputs.sha }}
fetch-depth: 1
persist-credentials: false

- name: Exchange OpenCode app token for scheduler writes
id: scheduler_app_token
env:
OIDC_AUDIENCE: opencode-github-action
OPENCODE_API_BASE_URL: https://api.opencode.ai
run: |
set -euo pipefail
mark_unavailable() {
echo "available=false" >>"$GITHUB_OUTPUT"
}
request_url="${ACTIONS_ID_TOKEN_REQUEST_URL}"
separator="&"
case "$request_url" in
*\?*) ;;
*) separator="?" ;;
esac
oidc_response="$(
curl -fsS \
-H "Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \
"${request_url}${separator}audience=${OIDC_AUDIENCE}"
)" || { mark_unavailable; exit 0; }
oidc_token="$(jq -r '.value // empty' <<<"$oidc_response")"
[ -n "$oidc_token" ] || { mark_unavailable; exit 0; }
token_response="$(
curl -fsS \
-X POST \
-H "Authorization: Bearer ${oidc_token}" \
"${OPENCODE_API_BASE_URL}/exchange_github_app_token"
)" || { mark_unavailable; exit 0; }
app_token="$(jq -r '.token // empty' <<<"$token_response")"
[ -n "$app_token" ] || { mark_unavailable; exit 0; }
echo "::add-mask::$app_token"
{
echo "available=true"
echo "token=$app_token"
} >>"$GITHUB_OUTPUT"

- name: Self-test NVIDIA NIM scheduler contract
run: python3 scripts/ci/pr_review_fix_scheduler_nim.py --self-test

- name: Dispatch bounded NVIDIA NIM review repair
env:
GH_TOKEN: >-
${{ steps.scheduler_app_token.outputs.token || secrets.PR_REVIEW_MERGE_TOKEN ||
secrets.OPENCODE_APPROVE_TOKEN || github.token }}
run: |
set -euo pipefail
args=(
--repo "$TARGET_REPOSITORY"
--base-branch "$DEFAULT_BRANCH"
--max-prs "$MAX_PRS"
--max-dispatches "$MAX_DISPATCHES"
--retry-hours "$RETRY_HOURS"
--autofix-repository "$AUTOFIX_REPOSITORY"
--autofix-workflow "$AUTOFIX_WORKFLOW"
)
if [ "$DRY_RUN" = "true" ]; then
args+=(--dry-run)
fi
python3 scripts/ci/pr_review_fix_scheduler_nim.py "${args[@]}"
Loading
Loading