-
Notifications
You must be signed in to change notification settings - Fork 0
ci: schedule hourly NVIDIA NIM commercial maintenance #535
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
2c1082e
ci: schedule hourly NVIDIA NIM PR maintenance
seonghobae 9a73a9f
test(ci): lock hourly commercial maintenance contract
seonghobae 0f32b6f
docs(ci): document hourly commercial maintenance
seonghobae 63ee774
docs(changelog): record hourly NVIDIA NIM maintenance
seonghobae 85587c5
fix(ci): minimize hourly maintenance token permissions
seonghobae 43f55d5
test(ci): enforce read-only leaf scheduler permissions
seonghobae 2786508
fix(ci): validate reusable workflow runtime ownership
seonghobae File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| name: Hourly Commercial Maintenance | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: "41 * * * *" | ||
| workflow_dispatch: | ||
| inputs: | ||
| dry_run: | ||
| description: Inspect the queue without dispatching a repair | ||
| required: false | ||
| default: false | ||
| type: boolean | ||
|
|
||
| concurrency: | ||
| group: hourly-commercial-maintenance-${{ github.repository }} | ||
| cancel-in-progress: true | ||
|
|
||
| permissions: {} | ||
|
|
||
| jobs: | ||
| review-repair: | ||
| permissions: | ||
| actions: read | ||
| contents: read | ||
| id-token: write | ||
| issues: read | ||
| pull-requests: read | ||
| statuses: read | ||
| uses: ContextualWisdomLab/.github/.github/workflows/nvidia-nim-pr-maintenance.yml@2ebda8063d3c541e2552dc474c3c8601ddc986f8 | ||
| with: | ||
| target_repository: ContextualWisdomLab/newsdom-api | ||
| base_branch: develop | ||
| dry_run: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run || false }} | ||
| max_prs: "50" | ||
| max_dispatches: "1" | ||
| retry_hours: "1" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| # Hourly commercial maintenance | ||
|
|
||
| ## Purpose | ||
|
|
||
| NewsDOM invokes the organization-owned pull-request maintenance control plane once per hour. The leaf repository supplies only its repository identity, `develop` integration branch, cadence, and bounded queue limits. Review parsing, exact-head selection, repair dispatch, credential separation, and OpenCode model configuration remain owned by `ContextualWisdomLab/.github`. | ||
|
|
||
| ## Schedule and single-flight behavior | ||
|
|
||
| - Schedule: minute 41 of every hour. | ||
| - Maximum inspected pull requests: 50. | ||
| - Maximum repair dispatches per run: 1. | ||
| - Same-head repair retry floor: 1 hour. | ||
| - Concurrency: one active run per repository; a newer scheduler invocation cancels an older scheduler invocation before another repair can be dispatched. | ||
| - Manual mode: `workflow_dispatch` exposes `dry_run`, which reads the queue and records decisions without dispatching a worker. | ||
|
|
||
| The central worker uses OpenCode with the organization secret `NVIDIA_NIM_API_KEY`. The leaf workflow never receives that secret and never uses `COPILOT_GITHUB_TOKEN`. GitHub transport authorization is obtained centrally through the existing OpenCode App OIDC exchange or an explicitly declared maintenance token fallback. The read-only OpenCode and Noema review workflows are unchanged. | ||
|
|
||
| ## Merge and safety boundaries | ||
|
|
||
| The hourly workflow does not merge a pull request. It only dispatches a conservative repair when the current head has actionable, file-scoped review evidence or meets the central conflict-resolution contract. A repair: | ||
|
|
||
| 1. revalidates the live base and head SHAs; | ||
| 2. accepts only same-repository heads; | ||
| 3. gives OpenCode access only to the approved paths; | ||
| 4. denies model shell, task, network, LSP, and external-directory access; | ||
| 5. refuses a push if the head moves; | ||
| 6. produces a new head that must pass all repository checks and independent review; and | ||
| 7. cannot approve, publish, release, or weaken branch protection. | ||
|
|
||
| ## MSA boundary | ||
|
|
||
| This workflow is a leaf adapter, not a second implementation. It pins the reusable central workflow by full commit SHA. Other CWL components can adopt the same central component while supplying their own target repository, default branch, and schedule. NewsDOM continues to operate independently as a FastAPI PDF-to-DOM service and as a naruon-compatible sidecar. | ||
|
|
||
| ## Operational prerequisites | ||
|
|
||
| - The organization OpenCode GitHub App must be able to read and write the target pull-request head. | ||
| - The central `.github` repository must expose the pinned reusable workflow and worker commit. | ||
| - `NVIDIA_NIM_API_KEY` must be available to the central worker repository. | ||
| - Required checks and independent-review rules remain active. | ||
|
|
||
| If the central app-token exchange is unavailable and no optional maintenance token is configured, cross-repository dispatch fails closed. It does not fall back to Copilot or another inference provider. | ||
|
|
||
| ## Verification | ||
|
|
||
| Before enabling the schedule on `develop`, verify: | ||
|
|
||
| - the caller pins exactly one 40-character central commit SHA; | ||
| - no model or Copilot credential appears in the leaf workflow; | ||
| - the workflow grants no `contents: write` or `pull-requests: write` permission; | ||
| - static contracts pass under the repository's 100% coverage gate; | ||
| - the central workflow passes its own unit, security, and independent-review gates; and | ||
| - one manual dry run records a bounded no-write queue decision. | ||
|
|
||
| ## Rollback | ||
|
|
||
| Delete or disable `.github/workflows/hourly-commercial-maintenance.yml`. This does not affect application runtime, existing review workflows, branch protection, or manually initiated maintenance. Revert only the leaf adapter; the central component can remain available to other repositories. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| """Contracts for NewsDOM's hourly commercial-maintenance caller.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from pathlib import Path | ||
| import re | ||
|
|
||
|
|
||
| REPOSITORY_ROOT = Path(__file__).resolve().parents[1] | ||
| WORKFLOW_PATH = REPOSITORY_ROOT / ".github/workflows/hourly-commercial-maintenance.yml" | ||
|
|
||
|
|
||
| def _workflow_text() -> str: | ||
| """Return the tracked hourly workflow text.""" | ||
|
|
||
| return WORKFLOW_PATH.read_text(encoding="utf-8") | ||
|
|
||
|
|
||
| def test_hourly_cadence_is_single_flight() -> None: | ||
| """The repository should request one non-overlapping maintenance run each hour.""" | ||
|
|
||
| workflow = _workflow_text() | ||
|
|
||
| assert 'cron: "41 * * * *"' in workflow | ||
| assert "hourly-commercial-maintenance-${{ github.repository }}" in workflow | ||
| assert "cancel-in-progress: true" in workflow | ||
| assert 'max_dispatches: "1"' in workflow | ||
| assert 'retry_hours: "1"' in workflow | ||
|
|
||
|
|
||
| def test_caller_targets_newsdom_develop_through_immutable_central_source() -> None: | ||
| """The leaf workflow must retain only local routing and pin central behavior by SHA.""" | ||
|
|
||
| workflow = _workflow_text() | ||
| match = re.search( | ||
| r"uses: ContextualWisdomLab/\.github/\.github/workflows/" | ||
| r"nvidia-nim-pr-maintenance\.yml@([0-9a-f]{40})", | ||
| workflow, | ||
| ) | ||
|
|
||
| assert match is not None | ||
| assert match.group(1) == "2ebda8063d3c541e2552dc474c3c8601ddc986f8" | ||
| assert "target_repository: ContextualWisdomLab/newsdom-api" in workflow | ||
| assert "base_branch: develop" in workflow | ||
| assert "uses: ./.github/workflows/" not in workflow | ||
| assert "@main" not in workflow | ||
|
|
||
|
|
||
| def test_caller_grants_only_read_and_oidc_permissions() -> None: | ||
| """The leaf token must be read-only except for the OIDC identity exchange.""" | ||
|
|
||
| workflow = _workflow_text() | ||
|
|
||
| assert "permissions: {}" in workflow | ||
| required_permissions = ( | ||
| "actions: read", | ||
| "contents: read", | ||
| "id-token: write", | ||
| "issues: read", | ||
| "pull-requests: read", | ||
| "statuses: read", | ||
| ) | ||
| for permission in required_permissions: | ||
| assert permission in workflow | ||
|
|
||
| forbidden_permissions = ( | ||
| "actions: write", | ||
| "contents: write", | ||
| "issues: write", | ||
| "pull-requests: write", | ||
| "statuses: write", | ||
| ) | ||
| for permission in forbidden_permissions: | ||
| assert permission not in workflow | ||
|
|
||
| assert "secrets: inherit" not in workflow | ||
|
|
||
|
|
||
| def test_caller_never_uses_copilot_or_model_credentials() -> None: | ||
| """Inference credentials belong to the central NIM worker, not the leaf scheduler.""" | ||
|
|
||
| workflow = _workflow_text() | ||
|
|
||
| assert "COPILOT_GITHUB_TOKEN" not in workflow | ||
| assert "NVIDIA_NIM_API_KEY" not in workflow | ||
| assert "NVIDIA_API_KEY" not in workflow | ||
| assert "STRIX_GITHUB_MODELS_TOKEN" not in workflow | ||
| assert "models.github.ai" not in workflow | ||
|
|
||
|
|
||
| def test_manual_dry_run_is_available_without_changing_schedule_behavior() -> None: | ||
| """Operators should be able to inspect the queue without dispatching repairs.""" | ||
|
|
||
| workflow = _workflow_text() | ||
|
|
||
| assert "workflow_dispatch:" in workflow | ||
| assert "dry_run:" in workflow | ||
| assert "type: boolean" in workflow | ||
| assert "github.event_name == 'workflow_dispatch'" in workflow |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.