Skip to content

Fix 403 when posting lint comments on fork PRs - #466

Merged
openshift-merge-bot[bot] merged 5 commits into
openshift-eng:mainfrom
stbenjam:fix-lint-403-fork-prs
May 12, 2026
Merged

openshift-merge-bot[bot] merged 5 commits into
openshift-eng:mainfrom
stbenjam:fix-lint-403-fork-prs

Conversation

@stbenjam

@stbenjam stbenjam commented May 12, 2026

Copy link
Copy Markdown
Member

Summary

  • Keep pull_request trigger (read-only token, safe for fork PRs that may run custom linter rules via subprocess)
  • Add a new lint-review.yml workflow that triggers on workflow_run completion and uses skillsaw's review/ action to post PR comments with a write-capable token
  • Remove pull-requests: write from the lint job since it no longer posts comments directly
  • Depends on Support two-workflow pattern for fork PR comments stbenjam/skillsaw#140 (skillsaw support for artifact-based review)

Why not pull_request_target?

.skillsaw-custom.py runs subprocess.run(["python3", ...]) on scripts from the checked-out repo. With pull_request_target, a malicious fork PR could replace those scripts and get arbitrary code execution with a write token.

Test plan

  • Merge skillsaw PR first, update SHA references
  • Verify fork PRs get inline lint review comments without 403
  • Verify push-to-main lint still works
  • Verify linter text output is visible in CI logs

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Tightened permissions for the pull-request linting job to reduce granted access.
    • Added a separate lint-review workflow that runs after lint checks on pull requests and posts automated review comments.
    • Improves visibility and reliability of lint feedback during pull request reviews.

Switch from pull_request to pull_request_target so the GITHUB_TOKEN
has write access for fork PRs. Explicitly checkout the PR head SHA
since pull_request_target defaults to the base branch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openshift-ci
openshift-ci Bot requested review from Prashanth684 and enxebre May 12, 2026 18:45
@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label May 12, 2026
@coderabbitai

coderabbitai Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c989af78-efe7-4ec4-bc39-224c499e8aba

📥 Commits

Reviewing files that changed from the base of the PR and between 9d8dd00 and 5f58193.

📒 Files selected for processing (1)
  • .github/workflows/lint-review.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/lint-review.yml

Walkthrough

Removes pull-requests: write from the lint job in .github/workflows/lint-plugins.yml and adds a new Lint Review workflow .github/workflows/lint-review.yml that triggers on completion of Lint Plugins for pull requests and posts review comments (workflow requests pull-requests: write).

Changes

Lint Plugins permission change

Layer / File(s) Summary
Permissions reduction (lint job)
.github/workflows/lint-plugins.yml
Removes pull-requests: write from the permissions block for the lint job, leaving contents: read. Also updates the pinned stbenjam/skillsaw action commit hash used by the Run skillsaw step.

Lint Review workflow addition

Layer / File(s) Summary
Workflow trigger and guard
.github/workflows/lint-review.yml
Adds Lint Review workflow with workflow_run trigger for the Lint Plugins workflow scoped to types: [completed] and guarded by if: github.event.workflow_run.event == 'pull_request'.
Job and permissions
.github/workflows/lint-review.yml
Introduces review job that requests permissions: pull-requests: write so it can post PR review comments.
Checkout and review step
.github/workflows/lint-review.yml
review job checks out the repo and runs stbenjam/skillsaw/review pinned to a specific commit to post review comments to the triggering pull request.

Sequence Diagram

sequenceDiagram
    participant LintPlugins as Lint Plugins workflow
    participant GH as GitHub Actions
    participant LintReview as Lint Review workflow
    participant Skillsaw as stbenjam/skillsaw/review
    LintPlugins->>GH: complete run
    GH->>LintReview: workflow_run (completed)
    LintReview->>GH: check event == 'pull_request'
    LintReview->>GH: checkout repository (GITHUB_TOKEN)
    LintReview->>Skillsaw: run review action (uses pull-requests: write)
    Skillsaw->>GH: create PR review comments
Loading

Estimated Code Review Effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested Labels

lgtm, ok-to-test

Suggested Reviewers

  • mrunalp
  • bryan-cox
  • enxebre
🚥 Pre-merge checks | ✅ 10
✅ Passed checks (10 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main fix: resolving 403 errors when posting lint comments on fork PRs, which directly aligns with the primary objective and changes in the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No Real People Names In Style References ✅ Passed No real people names found in style references, plugin commands, or skill documentation. PR contains only GitHub Actions workflow configuration files.
No Assumed Git Remote Names ✅ Passed The PR avoids hardcoded git remote names. validate-plugin-version.yml discovers the remote dynamically using git remote and uses it in all commands. No hardcoded "origin" or "upstream" strings.
Git Push Safety Rules ✅ Passed No unsafe git push operations detected. PR contains no 'git push' commands, force push flags, or main/master pushes. Workflows follow security best practices with proper permissions.
No Untrusted Mcp Servers ✅ Passed No MCP server installations found. PR only modifies GitHub Actions workflows for linting/review without introducing any MCP servers from trusted or untrusted sources.
Ai-Helpers Overlap Detection ✅ Passed PR only modifies workflow files (.github/workflows/*.yml), not ai-helpers functional content. Check excludes non-functional docs per Phase 1 instructions.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/lint-plugins.yml (1)

4-20: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Critical: pull_request_target with checkout of untrusted PR code enables arbitrary code execution.

This workflow has an exploitable vulnerability. The pull_request_target trigger grants the job a write-capable GITHUB_TOKEN, and the workflow checks out untrusted code from github.event.pull_request.head.sha. More critically, skillsaw's custom rule in .skillsaw-custom.py actively executes arbitrary Python scripts from the checked-out repository (lines 54–60 and 74–80 in PluginsDocUpToDateRule.check()):

subprocess.run(["python3", str(script_path)], ...)  # Runs scripts/generate_plugin_docs.py from PR
subprocess.run(["python3", str(website_script_path)], ...)  # Runs scripts/build-website.py from PR

An attacker can submit a PR with a malicious scripts/generate_plugin_docs.py file. When the workflow runs, skillsaw will execute it with write access to the repository and secrets—enabling repository compromise.

Required fix: Either (1) remove pull_request_target and use pull_request instead, or (2) implement the two-workflow pattern: an unprivileged pull_request workflow that runs the linter, and a separate workflow_run-triggered workflow that posts comments.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/lint-plugins.yml around lines 4 - 20, The workflow uses
the dangerous pull_request_target trigger and checks out PR HEAD via
actions/checkout with ref: ${{ github.event.pull_request.head.sha || github.sha
}}, which combined with .skillsaw-custom.py's PluginsDocUpToDateRule.check()
that calls subprocess.run(["python3", str(script_path)], ...) and
subprocess.run(["python3", str(website_script_path)], ...) allows execution of
untrusted PR code with elevated token permissions; fix by replacing
pull_request_target with pull_request (or switch to the two-workflow pattern: an
unprivileged pull_request job to run the linter and a separate
workflow_run-triggered job to post comments), and ensure the checkout step does
not fetch PR HEAD code with elevated permissions (use default checkout behavior
for pull_request or fetch only safe refs); update the workflow triggers and the
actions/checkout usage accordingly so PluginsDocUpToDateRule.check() runs only
on code from the trusted repo context or on the unprivileged runner.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/lint-plugins.yml:
- Around line 4-20: The workflow uses the dangerous pull_request_target trigger
and checks out PR HEAD via actions/checkout with ref: ${{
github.event.pull_request.head.sha || github.sha }}, which combined with
.skillsaw-custom.py's PluginsDocUpToDateRule.check() that calls
subprocess.run(["python3", str(script_path)], ...) and
subprocess.run(["python3", str(website_script_path)], ...) allows execution of
untrusted PR code with elevated token permissions; fix by replacing
pull_request_target with pull_request (or switch to the two-workflow pattern: an
unprivileged pull_request job to run the linter and a separate
workflow_run-triggered job to post comments), and ensure the checkout step does
not fetch PR HEAD code with elevated permissions (use default checkout behavior
for pull_request or fetch only safe refs); update the workflow triggers and the
actions/checkout usage accordingly so PluginsDocUpToDateRule.check() runs only
on code from the trusted repo context or on the unprivileged runner.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: af79568e-1cf5-4bc9-9ba9-7da1a7754542

📥 Commits

Reviewing files that changed from the base of the PR and between 527a327 and d26115b.

📒 Files selected for processing (1)
  • .github/workflows/lint-plugins.yml

Revert pull_request_target — it's unsafe because .skillsaw-custom.py
runs subprocess on scripts from the checked-out code, which would
execute with a write-capable token on fork PRs.

Instead, keep pull_request (read-only token) for linting. The skillsaw
action uploads the report as an artifact. A new lint-review.yml
workflow triggers on workflow_run completion and uses the skillsaw
review action to post PR comments with a privileged token, without
ever checking out untrusted code.

Also removes pull-requests: write from the lint job since it no longer
posts comments directly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/lint-review.yml:
- Line 10: The workflow's if guard only checks github.event.workflow_run.event
and should also require the upstream run succeeded; update the conditional on
the job to include github.event.workflow_run.conclusion == 'success' (e.g.,
replace or extend the existing if expression that references
github.event.workflow_run.event to also check
github.event.workflow_run.conclusion == 'success') so the review job only runs
for successful upstream lint runs.
- Around line 12-20: The permissions block currently only grants pull-requests:
write which removes other scopes causing actions/checkout and artifact retrieval
to fail; either remove the unnecessary checkout step (the actions/checkout
usage) if the review action doesn’t need the repository files, or update the
permissions to include contents: read and actions: read so actions/checkout and
stbenjam/skillsaw/review can operate; modify the permissions entry (not the
step) and/or delete the Checkout code step accordingly to restore required
scopes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: bc01e6cd-138c-4f6c-97d6-5bd842e32c94

📥 Commits

Reviewing files that changed from the base of the PR and between d26115b and 1030a9c.

📒 Files selected for processing (2)
  • .github/workflows/lint-plugins.yml
  • .github/workflows/lint-review.yml
💤 Files with no reviewable changes (1)
  • .github/workflows/lint-plugins.yml

Comment thread .github/workflows/lint-review.yml
Comment thread .github/workflows/lint-review.yml Outdated
stbenjam and others added 3 commits May 12, 2026 19:06
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cblecker

Copy link
Copy Markdown
Collaborator

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label May 12, 2026
@openshift-ci

openshift-ci Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: cblecker, stbenjam

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-merge-bot
openshift-merge-bot Bot merged commit 2550735 into openshift-eng:main May 12, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants