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
14 changes: 6 additions & 8 deletions .github/workflows/pr-review-fix-scheduler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,6 @@ on:
required: false
default: ""
type: string
canonical_ref:
description: Ref of ContextualWisdomLab/.github to use for scheduler code
required: false
default: "main"
type: string
repository_dispatch:
types: [pr-review-fix-scheduler]
schedule:
Expand Down Expand Up @@ -83,13 +78,16 @@ jobs:
RETRY_HOURS: ${{ github.event.client_payload.retry_hours || inputs.retry_hours || '24' }}
AUTOFIX_WORKFLOW: pr-review-autofix.yml
AUTOFIX_REPOSITORY: ContextualWisdomLab/.github
CANONICAL_REF: main
steps:
- name: Checkout canonical scheduler
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: ContextualWisdomLab/.github
ref: ${{ env.CANONICAL_REF }}
# In a reusable workflow, the ordinary github context belongs to the
# caller. The job workflow context identifies the called workflow's
# repository and immutable resolved SHA, so no caller input or branch
# can select the privileged scheduler implementation.
repository: ${{ job.workflow_repository }}
ref: ${{ job.workflow_sha }}
fetch-depth: 1
persist-credentials: false

Expand Down
42 changes: 42 additions & 0 deletions tests/test_pr_review_fix_scheduler_source_pin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Supply-chain contract for the reusable PR-review autofix scheduler."""

from __future__ import annotations

from pathlib import Path


_REPO_ROOT = Path(__file__).resolve().parents[1]
_WORKFLOW = _REPO_ROOT / ".github" / "workflows" / "pr-review-fix-scheduler.yml"


def _workflow_text() -> str:
"""Read the reusable scheduler workflow as UTF-8 text."""
return _WORKFLOW.read_text(encoding="utf-8")


def test_reusable_scheduler_checks_out_the_called_workflow_sha():
"""Privileged scheduler code comes from the immutable called-workflow revision."""
workflow = _workflow_text()
assert "repository: ${{ job.workflow_repository }}" in workflow
assert "ref: ${{ job.workflow_sha }}" in workflow
assert "persist-credentials: false" in workflow


def test_reusable_scheduler_source_is_not_caller_input_controlled():
"""No caller-supplied ref or ordinary caller GitHub SHA selects trusted code."""
workflow = _workflow_text()
assert "canonical_ref:" not in workflow
assert "inputs.canonical_ref" not in workflow
assert "github.event.client_payload.canonical_ref" not in workflow
assert "ref: ${{ env.CANONICAL_REF }}" not in workflow
assert "ref: ${{ github.sha }}" not in workflow


def test_reusable_scheduler_retains_least_privilege_and_bounded_dispatch():
"""Source pinning does not broaden token scope or queue fan-out."""
workflow = _workflow_text()
assert "contents: write" not in workflow
assert "pull-requests: write" not in workflow
assert "MAX_DISPATCHES:" in workflow
assert "RETRY_HOURS:" in workflow
assert "cancel-in-progress: true" in workflow
Loading