chore(ci): rename PR welcome workflow and add code of conduct - #8
Conversation
- Rename `.github/workflows/pr-welcome.yml` to `pr-guidance.yml` - Add standard `CODE_OF_CONDUCT.md` to the repository
The pull_request event runs with a restricted token that cannot create comments on PRs from forks. Switching to pull_request_target runs the workflow in the base repository's context with proper write permissions, enabling the guidance comment to be posted on fork PRs.
📝 WalkthroughSummary by CodeRabbit
WalkthroughRemoves the existing ChangesPR Guidance Workflow Replacement
Code of Conduct Addition
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: e7e7eaf4-cf61-40f2-8dd6-1a65b5faa9b3
📒 Files selected for processing (3)
.github/workflows/pr-guidance.yml.github/workflows/pr-welcome.ymlCODE_OF_CONDUCT.md
💤 Files with no reviewable changes (1)
- .github/workflows/pr-welcome.yml
| #pull_request_target: | ||
| pull_request: | ||
| types: [opened, ready_for_review] |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/pr-guidance.ymlRepository: Atliac/crate-template
Length of output: 9479
🌐 Web query:
pull_request vs pull_request_target GitHub Actions fork PRs permissions write comments
💡 Result:
The fundamental difference between pull_request and pull_request_target lies in the security context of the workflow execution, particularly when handling pull requests from forks [1][2][3]. pull_request: This event runs the workflow using the code from the pull request's merge commit [1][4]. Because this code is provided by an untrusted source (the fork), GitHub automatically restricts the workflow to a read-only GITHUB_TOKEN and prevents it from accessing repository secrets [1][2][4]. This makes it difficult to perform actions that require write permissions, such as posting comments or applying labels to the pull request [4]. pull_request_target: This event runs the workflow in the context of the base repository's default branch [1][2]. Because the workflow code is trusted (it comes from your repository), it is granted a read/write GITHUB_TOKEN and access to secrets [1][4][5]. This allows you to perform privileged tasks like commenting on or labeling the pull request [4][5]. Security Risks and Best Practices: Using pull_request_target introduces significant security risks if not managed carefully [2][6][5]. If a workflow triggered by pull_request_target explicitly checks out and runs code from the untrusted pull request, an attacker can exploit the workflow's elevated permissions to steal secrets, modify the repository, or compromise connected systems [3][6][5]. This is known as a pwn request [6][5]. To use these events safely: 1. Prefer pull_request whenever possible [1][7][5]. 2. If you must use pull_request_target for tasks like commenting or labeling, ensure the workflow never checks out or executes code from the pull request head [1][5]. 3. If you need to both check the PR code and perform privileged actions, use a split-workflow approach [8][5]: - Use a standard pull_request workflow to test/validate the PR code in an unprivileged, isolated environment [8][5]. - Use a second workflow, triggered by workflow_run, which can access the artifacts produced by the first workflow and perform privileged actions (like commenting) securely [8][5]. 4. Be aware that actions/checkout (v7+) now includes protections to fail by default when attempting to check out fork code in a pull_request_target context, requiring explicit opt-in (via allow-unsafe-pr-checkout) if necessary [6]. Always verify that your workflow adheres to the principle of least privilege [1][7].
Citations:
- 1: https://docs.github.com/en/actions/reference/security/securely-using-pull_request_target
- 2: https://docs.github.com/actions/using-workflows/events-that-trigger-workflows
- 3: https://codeql.github.com/codeql-query-help/actions/actions-untrusted-checkout-critical/
- 4: https://stackoverflow.com/questions/74957218/what-is-the-difference-between-pull-request-and-pull-request-target-event-in-git
- 5: https://saschb2b.com/blog/pull-request-target-trap
- 6: https://github.blog/changelog/2026-06-18-safer-pull_request_target-defaults-for-github-actions-checkout/
- 7: https://github.blog/changelog/2025-11-07-actions-pull_request_target-and-environment-branch-protections-changes/
- 8: https://stackoverflow.com/questions/69499645/how-to-securely-allow-github-actions-to-check-pr-and-post-results-in-comment
Use pull_request_target for fork-compatible comment posting.
Line 5 currently uses pull_request, which restricts the GITHUB_TOKEN to read-only when triggered from fork-originated PRs. This prevents the workflow from posting comments despite the issues: write permission. Switching to pull_request_target is safe here since the workflow does not check out or execute untrusted code—it only uses context metadata.
Additionally, line 187 uses single quotes rather than backticks, so the ${context.repo.owner} and ${context.repo.repo} variables will not be interpolated and will display as literal text in the comment.
Suggested fixes
on:
- `#pull_request_target`:
- pull_request:
+ pull_request_target:
types: [opened, ready_for_review]- '- [Project Documentation](https://github.com/${context.repo.owner}/${context.repo.repo}`#readme`)',
+ `- [Project Documentation](https://github.com/${context.repo.owner}/${context.repo.repo}`#readme`)`,📝 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.
| #pull_request_target: | |
| pull_request: | |
| types: [opened, ready_for_review] | |
| on: | |
| pull_request_target: | |
| types: [opened, ready_for_review] |
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Post guidance comment | ||
| uses: actions/github-script@v7 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/pr-guidance.yml | head -30Repository: Atliac/crate-template
Length of output: 1131
🏁 Script executed:
rg "actions/github-script" --type yamlRepository: Atliac/crate-template
Length of output: 214
🌐 Web query:
GitHub Actions pinning commit SHA vs tag best practices security
💡 Result:
Pinning GitHub Actions to a full-length commit SHA (40 characters) is considered the industry standard and most secure practice [1][2][3][4]. While tags are convenient, they are mutable references that can be moved or deleted, making them susceptible to supply chain attacks where malicious code is injected into an existing tag [1][5][6]. Best Practices for GitHub Actions Pinning: 1. Use Full-Length Commit SHAs: Always reference third-party actions using the full 40-character commit SHA [3][7]. This ensures the code executed is immutable and identical to what you reviewed [8][5][9]. 2. Maintain Human-Readability: When pinning to a SHA, include the corresponding version tag in a comment on the same line (e.g., uses: owner/repo@abcdef123... # v1.2.3) [8][3][4]. This practice provides context and enables automated dependency management tools like Dependabot and Renovate to correlate the SHA with semver releases [8][6][7]. 3. Automate Updates: SHA pinning introduces a maintenance obligation. Use tools such as Dependabot or Renovate to automatically open pull requests for new versions [8][6][4]. Renovate, for instance, can be configured to keep SHA pins up-to-date with tag releases [6][4]. 4. Enforce via Policy: Use GitHub’s organization-level policy to mandate SHA pinning across all repositories [1][2][5]. This ensures compliance and prevents the accidental introduction of non-pinned actions [2][4]. 5. Use Verification Tools: Implement CI checks using tools like step-security/github-actions-ensure-sha-pinned-actions to fail workflows that use mutable references (tags/branches) instead of full-length SHAs [10][7][4]. While GitHub-owned actions (e.g., actions/checkout) are generally safer because they are covered by GitHub's internal supply chain controls, applying consistent SHA pinning across all third-party dependencies is the recommended approach for maximum security [7]. Note that Dependabot does not generate security alerts for actions pinned to specific SHAs, as the immutability prevents it from automatically applying patches; you must manually review and merge dependency updates [1][8].
Citations:
- 1: https://docs.github.com/en/actions/reference/security/secure-use
- 2: https://github.blog/changelog/2025-08-15-github-actions-policy-now-supports-blocking-and-sha-pinning-actions/
- 3: https://docs.ozarksecuritylabs.com/supply-chain/tier-1-baseline/sha-pin-actions/
- 4: https://architecture.lullabot.com/adr/20260505-pin-github-actions-to-hash/
- 5: https://www.romainlespinasse.dev/posts/github-actions-commit-sha-pinning/
- 6: https://www.systemshardening.com/articles/cicd/github-actions-supply-chain-hardening/
- 7: https://safeguard.sh/resources/blog/how-to-pin-github-actions-to-shas-correctly
- 8: https://safeguard.sh/resources/blog/github-actions-pinning-sha-vs-tag
- 9: https://www.stepsecurity.io/blog/pinning-github-actions-for-enhanced-security-a-complete-guide
- 10: https://github.com/step-security/github-actions-ensure-sha-pinned-actions
Pin actions/github-script to a full commit SHA.
Line 18 uses a mutable tag (@v7). Pinning to an exact commit SHA is the industry-standard security practice to prevent supply chain attacks where malicious code could be injected into mutable tags. Include the version tag in a comment for readability and enable tools like Dependabot to track updates automatically.
🧰 Tools
🪛 zizmor (1.25.2)
[error] 18-18: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
Source: Linters/SAST tools
| const comments = await github.rest.issues.listComments({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: prNumber | ||
| }); | ||
|
|
||
| const signature = 'Automated message maintained by [Atliac]'; | ||
| const alreadyCommented = comments.data.some(comment => | ||
| comment.body.includes(signature) | ||
| ); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/pr-guidance.yml | sed -n '30,50p'Repository: Atliac/crate-template
Length of output: 903
🌐 Web query:
GitHub Actions Octokit pagination listComments default page size behavior
💡 Result:
The default page size (per_page) for GitHub API list endpoints, including those used to fetch issue comments, is 30 [1][2][3]. The maximum allowed value for the per_page parameter is 100 [4][3][5]. When using Octokit libraries, this behavior is inherited directly from the underlying GitHub REST API [6][7]. While the API default is 30, you can explicitly set the per_page parameter up to 100 in your requests to retrieve more items per page and reduce the number of API calls [4][7][3]. If you are using the Octokit pagination plugin (octokit.paginate), it will automatically handle multiple requests to fetch all pages until the end, regardless of the per_page setting [1][7][8]. Many developers choose to set per_page to 100 when using pagination to minimize the number of network requests and stay within rate limits more efficiently [4][9][10].
Citations:
- 1: https://octokit.github.io/rest.js/
- 2: https://actions-cool.github.io/octokit-rest/guide/05_pagination/
- 3: https://docs.github.com/en/rest/issues/comments?apiVersion=--
- 4: https://github.com/octokit/plugin-paginate-rest.js/
- 5: https://developer.github.com/v3/repos/comments
- 6: Description about the default value of the
per_pageoption octokit/octokit.rb#1215 - 7: https://docs.github.com/en/rest/using-the-rest-api/using-pagination-in-the-rest-api
- 8: https://github.com/github/docs/blob/main/content/rest/using-the-rest-api/using-pagination-in-the-rest-api.md
- 9: https://github.com/octokit/plugin-paginate-rest.js/tree/main
- 10: How do I get the result of octokit.issues.listComments as a stream? octokit/octokit.js#2724
🌐 Web query:
github.paginate() Octokit API return value structure array vs object
💡 Result:
The octokit.paginate method always returns an array of items [1][2]. While some GitHub REST API endpoints return a raw JSON object (which may contain the array of results under a specific key, such as "items", "commits", or "installations"), octokit.paginate normalizes these responses [3][4][2]. It accumulates the paginated results and resolves with a single, flattened array containing all items gathered across all pages [3][1][2]. Key points regarding the return structure: - Consistency: Unlike octokit.request, which returns a response object containing { data, headers, status, url }, octokit.paginate resolves directly with the array of items [2]. - Normalization: Even if an API endpoint returns an object wrapper, octokit.paginate automatically extracts the relevant array [1][2]. - Map Function: If you provide an optional map function, that function receives the full response object (including the data, headers, etc.), and the data property within that object is guaranteed to be the array of items, regardless of whether the raw API response was an array or an object [2]. You then return the mapped values, which are also collected into a final array [3][5][2].
Citations:
- 1: https://github.com/github/docs/blob/main/content/rest/using-the-rest-api/using-pagination-in-the-rest-api.md
- 2: https://octokit.github.io/rest.js/v22/
- 3: https://github.com/octokit/plugin-paginate-rest.js/
- 4: https://www.npmjs.com/package/@octokit/plugin-paginate-rest
- 5: https://octokit.github.io/rest.js/v16/
Paginate comment retrieval to check all existing comments before posting.
The current implementation on line 35 fetches only the default first 30 comments from the GitHub API. For PRs with more than 30 comments, the duplicate-signature check on line 42 will miss earlier comments and may post duplicates.
Use github.paginate() to fetch all comments across all pages. Note that paginate() returns a flat array directly (unlike listComments() which returns a response object), so adjust the data accessor from comments.data.some() to comments.some().
Suggested fix
- const comments = await github.rest.issues.listComments({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: prNumber
- });
+ const comments = await github.paginate(
+ github.rest.issues.listComments,
+ {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: prNumber,
+ per_page: 100
+ }
+ );
const signature = 'Automated message maintained by [Atliac]';
- const alreadyCommented = comments.data.some(comment =>
+ const alreadyCommented = comments.some(comment =>
comment.body.includes(signature)
);| '', | ||
| `- [Contributing Guidelines](${repoUrl}/CONTRIBUTING.md)`, | ||
| `- [Code of Conduct](${repoUrl}/CODE_OF_CONDUCT.md)`, | ||
| '- [Project Documentation](https://github.com/${context.repo.owner}/${context.repo.repo}#readme)', |
There was a problem hiding this comment.
Fix literal placeholder in Project Documentation link.
Line 187 is single-quoted, so ${context.repo.owner} and ${context.repo.repo} are not interpolated and the posted URL is broken.
Suggested fix
- '- [Project Documentation](https://github.com/${context.repo.owner}/${context.repo.repo}`#readme`)',
+ `- [Project Documentation](https://github.com/${context.repo.owner}/${context.repo.repo}`#readme`)`,📝 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.
| '- [Project Documentation](https://github.com/${context.repo.owner}/${context.repo.repo}#readme)', | |
| `- [Project Documentation](https://github.com/${context.repo.owner}/${context.repo.repo}`#readme`)`, |
| ## Enforcement | ||
|
|
||
| Instances of abusive, harassing, or otherwise unacceptable behavior may be | ||
| reported to the community leaders responsible for enforcement at | ||
| **[INSERT CONTACT METHOD, e.g., contact@yourdomain.com]**. | ||
| All complaints will be reviewed and investigated promptly and fairly. | ||
|
|
||
| All community leaders are obligated to respect the privacy and security of the | ||
| reporter of any incident. |
There was a problem hiding this comment.
Fill in the enforcement contact method placeholder.
Line 62 contains an unfilled placeholder: [INSERT CONTACT METHOD, e.g., contact@yourdomain.com]. This makes the enforcement section non-functional because contributors have no way to report violations. Replace this placeholder with an actual contact method (e.g., an email address, Discord channel, or link to a GitHub issue template) before publishing or activating the Code of Conduct.
Example fix for enforcement contact
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
-**[INSERT CONTACT METHOD, e.g., contact@yourdomain.com]**.
+**[INSERT ACTUAL CONTACT, e.g., conduct@myproject.dev or use the [Report CoC Violation](link-to-issue-template)]**.
All complaints will be reviewed and investigated promptly and fairly.Replace the bracketed text with your project's actual contact method. Common options:
- Email:
conduct@mydomain.com - GitHub issue: Link to a template-based issue creation URL
- Discussion forum or platform-specific reporting mechanism
.github/workflows/pr-welcome.ymltopr-guidance.ymlCODE_OF_CONDUCT.mdto the repository