Skip to content
Merged
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
65 changes: 65 additions & 0 deletions .github/assets/label_pr.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Filter function for labels we do not want on PRs automatically.
function shouldIncludeLabel(label) {
const isStatus = label.startsWith("S-");
const isPreventStale = label === "M-prevent-stale";
const isDifficulty = label.startsWith("D-");

return !isStatus && !isPreventStale && !isDifficulty;
}

// Get the issue number from an issue link in the forms
// `<keyword> <issue url>` or `<keyword> #<issue number>`.
function getIssueLink(repoUrl, body) {
if (!body) return undefined;

const urlPattern = new RegExp(
`(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) ${repoUrl}/issues/(?<issue_number>\\d+)`,
"i"
);
const issuePattern = new RegExp(
`(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) #(?<issue_number>\\d+)`,
"i"
);
Comment on lines +15 to +22
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Make issue-link regex more robust to formatting and URL matching.

Current patterns are fragile (single literal space) and repoUrl is injected unescaped into a regex. This can miss references in common PR body formatting and allow unintended matches.

💡 Proposed hardening
 function getIssueLink(repoUrl, body) {
   if (!body) return undefined;

+  const escapedRepoUrl = repoUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
   const urlPattern = new RegExp(
-    `(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) ${repoUrl}/issues/(?<issue_number>\\d+)`,
+    `\\b(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\\b\\s+${escapedRepoUrl}/issues/(?<issue_number>\\d+)\\b`,
     "i"
   );
   const issuePattern = new RegExp(
-    `(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) #(?<issue_number>\\d+)`,
+    `\\b(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\\b\\s+#(?<issue_number>\\d+)\\b`,
     "i"
   );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const urlPattern = new RegExp(
`(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) ${repoUrl}/issues/(?<issue_number>\\d+)`,
"i"
);
const issuePattern = new RegExp(
`(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) #(?<issue_number>\\d+)`,
"i"
);
const escapedRepoUrl = repoUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const urlPattern = new RegExp(
`\\b(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\\b\\s+${escapedRepoUrl}/issues/(?<issue_number>\\d+)\\b`,
"i"
);
const issuePattern = new RegExp(
`\\b(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\\b\\s+#(?<issue_number>\\d+)\\b`,
"i"
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/assets/label_pr.js around lines 15 - 22, The current regexes
urlPattern and issuePattern are fragile because they use a literal space and
inject repoUrl unescaped; update both to accept flexible whitespace (use \s+),
allow optional URL schemes and optional surrounding angle brackets, and escape
repoUrl before interpolation (add a helper like escapeRegExp to sanitize
repoUrl) so special characters don't break the RegExp; also consider using a
case-insensitive non-capturing group for verbs (e.g.
(?:close|closes|fixes|resolved)) and anchor or word-boundary the issue number
capture (?<issue_number>\d+) to avoid unintended matches.


const urlRe = body.match(urlPattern);
const issueRe = body.match(issuePattern);
if (urlRe?.groups?.issue_number) {
return urlRe.groups.issue_number;
} else {
return issueRe?.groups?.issue_number;
}
}

module.exports = async ({ github, context }) => {
try {
const prNumber = context.payload.pull_request.number;
const prBody = context.payload.pull_request.body;
const repo = context.repo;

const repoUrl = context.payload.repository.html_url;
const issueNumber = getIssueLink(repoUrl, prBody);
if (!issueNumber) {
console.log("No issue reference found in PR description.");
return;
}

const issue = await github.rest.issues.get({
...repo,
issue_number: issueNumber,
});

const issueLabels = issue.data.labels
.map((label) => label.name)
.filter(shouldIncludeLabel);
if (issueLabels.length > 0) {
await github.rest.issues.addLabels({
...repo,
issue_number: prNumber,
labels: issueLabels,
});
}
} catch (err) {
console.error("Failed to label PR");
console.error(err);
}
Comment on lines +61 to +64
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Do not swallow labeling failures silently.

Line 61-Line 64 only logs errors. If GitHub API calls fail, the workflow still appears successful and masking this breaks reliability of auto-labeling.

✅ Suggested fix
   } catch (err) {
     console.error("Failed to label PR");
     console.error(err);
+    throw err;
   }
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (err) {
console.error("Failed to label PR");
console.error(err);
}
} catch (err) {
console.error("Failed to label PR");
console.error(err);
throw err;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/assets/label_pr.js around lines 61 - 64, The catch block in
label_pr.js currently only logs errors in the catch (err) {
console.error("Failed to label PR"); console.error(err); } which swallows
failures; modify that catch to propagate the failure so the workflow fails —
either rethrow the error or set process.exitCode = 1 (or call process.exit(1))
after logging. Locate the try/catch around the PR labeling logic (the catch
handling the label API call) and change it to log the error then rethrow or set
a non-zero exit code to ensure CI/workflow reports failure.

};
23 changes: 23 additions & 0 deletions .github/workflows/label-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Label PRs

on:
pull_request:
types: [opened]

jobs:
label_prs:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
Comment on lines +10 to +12
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find .github/workflows -name "*label-pr*" -type f

Repository: morph-l2/morph-reth

Length of output: 93


🏁 Script executed:

cat -n .github/workflows/label-pr.yml

Repository: morph-l2/morph-reth

Length of output: 688


🏁 Script executed:

cat -n .github/assets/label_pr.js

Repository: morph-l2/morph-reth

Length of output: 2433


🌐 Web query:

GitHub Actions pull-requests write permission required addLabels

💡 Result:

Yes, GitHub Actions workflows require pull-requests: write permission to add labels to pull requests using the GITHUB_TOKEN. To add labels to a pull request (via the Issues API endpoint POST /repos/{owner}/{repo}/issues/{issue_number}/labels, since PRs are issues), declare the permission in your workflow YAML: permissions: pull-requests: write Example workflow step using gh pr edit or REST API: - name: Add label to PR run: gh pr edit ${{ github.event.pull_request.number }} --add-label "your-label" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} This grants the GITHUB_TOKEN write access for pull requests. For labeler actions or creating new labels (if they don't exist), issues: write may also be needed alongside pull-requests: write, as PRs leverage the Issues API internally. Official examples in GitHub Docs use issues: write for issue labeling (applicable to PRs), but pull-requests: write is standard and sufficient for adding existing labels to PRs per actions/labeler documentation and community usage. For forked PRs, use pull_request_target trigger with explicit permissions for write access.

Citations:


🌐 Web query:

GitHub API issues.addLabels pull request permission requirements

💡 Result:

The GitHub REST API endpoint for adding labels to issues or pull requests is POST /repos/{owner}/{repo}/issues/{issue_number}/labels. Pull requests use the issues endpoints since every pull request is an issue. Permissions required: - For fine-grained personal access tokens (PATs): issues:write or pull-requests:write permission. - For GitHub Apps: issues:write or pull-requests:write permission. - For classic PATs: repo scope (provides push access to the repository). - Users must have write (push) access to the repository. Without sufficient permissions, label changes are silently dropped or the request fails with 403/404. In GitHub Actions, use permissions: { issues: write } or { pull-requests: write }.

Citations:


Tighten job token scope to least privilege.

This job labels pull requests via the Issues API; pull-requests: write is redundant since the label operation uses issues.addLabels(). Keep issues: write and add explicit contents: read for the checkout action.

🔐 Suggested permissions block
     permissions:
+      contents: read
       issues: write
-      pull-requests: write
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
permissions:
issues: write
pull-requests: write
permissions:
contents: read
issues: write
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/label-pr.yml around lines 10 - 12, Update the workflow
permissions block to follow least-privilege: remove the unnecessary
pull-requests: write permission, keep issues: write for the labels API usage,
and add contents: read so the actions/checkout step has explicit read access to
the repository; adjust the permissions stanza that currently lists issues and
pull-requests and ensure actions/checkout can operate with contents: read
instead of granting broader pull-requests scope.

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Label PRs
uses: actions/github-script@v8
with:
script: |
const label_pr = require('./.github/assets/label_pr.js')
await label_pr({github, context})
Loading