Skip to content

feat(repo): add GitHub Actions workflow to validate PR titles - #1

Open
x56uwnhoff wants to merge 1 commit into
masterfrom
feat/pr-title-validation
Open

feat(repo): add GitHub Actions workflow to validate PR titles#1
x56uwnhoff wants to merge 1 commit into
masterfrom
feat/pr-title-validation

Conversation

@x56uwnhoff

@x56uwnhoff x56uwnhoff commented Aug 4, 2026

Copy link
Copy Markdown

Current Behavior

Currently, there is no automated check to ensure that PR titles follow our conventional commit format. This can lead to inconsistent PR titles that don't match our commit conventions.

Expected Behavior

With this change, all PR titles will be automatically validated against our git commit rules when a PR is:

  • Opened
  • Edited
  • Synchronized
  • Reopened

The check uses the existing scripts/commit-lint.js script to validate PR titles, ensuring they follow the same format as our commit messages (e.g., feat(scope): description, fix(scope): description, etc.).

Related Issue(s)

This was requested to improve PR quality and consistency across the repository.

Implementation Details

  • Added a new GitHub Actions workflow: .github/workflows/pr-title-validation.yml
  • The workflow writes the PR title and body to a temporary file in the format specified
  • Runs node ./scripts/commit-lint.js on the file to validate the PR title
  • The check will fail if the PR title doesn't match our conventional commit format
  • The workflow only runs for the nrwl repository owner (consistent with other workflows)

Test Plan

  • Tested locally with valid PR titles (e.g., feat(core): add new feature)
  • Tested locally with invalid PR titles (confirmed validation failure)
  • Tested with breaking change notation (fix(core)!: breaking change)
  • Test on actual PR once merged

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Added automated validation for pull request titles and descriptions.
    • Validation runs on pull request activity to help ensure submissions follow project conventions.

Adds a new PR check that validates PR titles match our git commit rules
using the existing commit-lint.js script. The workflow runs on PR events
and ensures all PR titles follow the conventional commit format.

🤖 Generated with [Claude Code](https://claude.ai/code)

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

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request adds a GitHub Actions workflow that runs scripts/commit-lint.js for pull request activity in nrwl repositories. The workflow checks out the base branch, uses Node.js 20, and lints the pull request title and body.

Changes

Pull request title validation

Layer / File(s) Summary
Workflow triggers and runtime setup
.github/workflows/pr-title-validation.yml
The workflow responds to pull request activity, applies repository-owner gating, checks out the base branch, and configures Node.js 20.
Pull request message linting
.github/workflows/pr-title-validation.yml
The workflow writes the pull request title and body to a temporary message file and runs scripts/commit-lint.js against it.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding a GitHub Actions workflow to validate pull request titles.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/pr-title-validation

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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/pr-title-validation.yml:
- Around line 29-33: Update the pull-request title validation flow around the
heredoc writing /tmp/pr-message.txt so it validates only
github.event.pull_request.title, excluding the pull-request body. Preserve the
existing commit-lint.js invocation while ensuring invalid title suffixes or
valid-looking lines in the body cannot satisfy the title check.
- Around line 9-13: Add workflow-level least-privilege permissions in the PR
title validation workflow by declaring contents read access near the workflow
configuration, before the jobs section. Keep the existing validate-pr-title job
unchanged.
- Around line 3-7: Remove either the pull_request or pull_request_target trigger
from the workflow, keeping only one event configuration with its existing
activity types to ensure pull request title validation runs once.
- Around line 15-19: Update the actions/checkout@v4 step in the workflow to set
persist-credentials to false alongside the existing ref configuration,
preventing the checkout action from storing the repository token in Git
configuration.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 99438903-f8fc-4daf-a4c5-1644365ee303

📥 Commits

Reviewing files that changed from the base of the PR and between 2c1461c and d994d90.

📒 Files selected for processing (1)
  • .github/workflows/pr-title-validation.yml

Comment on lines +3 to +7
on:
pull_request:
types: [opened, edited, synchronize, reopened]
pull_request_target:
types: [opened, edited, synchronize, reopened]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- workflow ---'
cat -n .github/workflows/pr-title-validation.yml

printf '%s\n' '--- workflow files and trigger references ---'
git ls-files '.github/workflows/*'
rg -n --glob '.github/workflows/*' 'pull_request_target|pull_request:|concurrency:|workflow_run|pr-title|title' .github/workflows

Repository: LLM-CR-EVAL/nx-242-cr1

Length of output: 3489


🌐 Web query:

GitHub Actions workflow both pull_request and pull_request_target same event two workflow runs documentation

💡 Result:

Yes, you can configure a single GitHub Actions workflow to be triggered by both pull_request and pull_request_target events [1][2]. You can include both in the on block of your workflow file [1]. When you define a workflow to listen for both events, a single pull request activity (such as opening or synchronizing a PR) can trigger two separate workflow runs: one for pull_request and one for pull_request_target [3][2]. Key differences to consider when using them together: 1. Context and Security: - pull_request: Runs the workflow code from the pull request's merge commit [4][3]. It is restricted to a read-only GITHUB_TOKEN and does not have access to repository secrets to prevent unauthorized code execution from forks [4][5]. - pull_request_target: Runs the workflow code from the target repository's base branch (the version of the code that is trusted) [4][3]. This allows the workflow to access repository secrets and a read/write GITHUB_TOKEN, making it suitable for tasks like labeling or commenting on PRs [3][2]. 2. Triggering: - Both events support the same activity types (such as opened, synchronize, and reopened) [6][2]. - If a pull request has a merge conflict, pull_request workflows will not run, but pull_request_target workflows will still trigger [6][2]. Because these two events run in different contexts, you should be careful if you use them in the same workflow. It is common practice to use conditional logic (e.g., if: github.event_name == 'pull_request') within your jobs or steps if you need to perform different actions depending on which event triggered the specific run [7]. Additionally, exercise extreme caution when using pull_request_target, as it executes code from your base branch while handling potentially untrusted data from a pull request [4][2]. Top results: [6][4][1][2]

Citations:


Keep only one pull request trigger.

The matching pull request event starts one run for pull_request and another for pull_request_target. Remove one trigger to prevent duplicate validation runs and check results.

🧰 Tools
🪛 zizmor (1.29.0)

[error] 3-7: use of fundamentally insecure workflow trigger (dangerous-triggers): pull_request_target is almost always used insecurely

(dangerous-triggers)

🤖 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/pr-title-validation.yml around lines 3 - 7, Remove either
the pull_request or pull_request_target trigger from the workflow, keeping only
one event configuration with its existing activity types to ensure pull request
title validation runs once.

Comment on lines +9 to +13
jobs:
validate-pr-title:
if: ${{ github.repository_owner == 'nrwl' }}
name: Validate PR Title
runs-on: ubuntu-latest

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
file=".github/workflows/pr-title-validation.yml"
printf '%s\n' '--- workflow ---'
cat -n "$file"
printf '%s\n' '--- permission and checkout references ---'
rg -n '^\s*permissions:|^\s+(contents|actions|pull-requests|statuses|checks):|actions/checkout|github\.token|gh |curl |git push|git commit' "$file" || true
printf '%s\n' '--- bounded structural check ---'
python3 - <<'PY'
from pathlib import Path
p = Path(".github/workflows/pr-title-validation.yml")
text = p.read_text()
lines = text.splitlines()
permissions = [i + 1 for i, line in enumerate(lines) if line.strip() == "permissions:"]
checkout = [i + 1 for i, line in enumerate(lines) if "actions/checkout" in line]
print({"permissions_lines": permissions, "checkout_lines": checkout})
PY

Repository: LLM-CR-EVAL/nx-242-cr1

Length of output: 1691


Security Misconfiguration (CWE-732): Incorrect Permission Assignment for Critical Resource

Reachability: External

Declare least-privilege permissions.

Add workflow-level permissions: contents: read. The workflow currently inherits repository or organization defaults, although it only needs read access to repository contents.

🤖 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/pr-title-validation.yml around lines 9 - 13, Add
workflow-level least-privilege permissions in the PR title validation workflow
by declaring contents read access near the workflow configuration, before the
jobs section. Keep the existing validate-pr-title job unchanged.

Source: Linters/SAST tools

Comment on lines +15 to +19
- name: Checkout code
uses: actions/checkout@v4
with:
# For pull_request_target, we need to checkout the base branch
ref: ${{ github.event.pull_request.base.ref }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- workflow files ---'
git ls-files '.github/workflows/pr-title-validation.yml' '.github/workflows/*' | sed -n '1,80p'
printf '%s\n' '--- target workflow ---'
cat -n .github/workflows/pr-title-validation.yml
printf '%s\n' '--- checkout and shell-related references ---'
rg -n -C 4 'actions/checkout|pull_request_target|run:|github\.event|commit-lint|commit message|title' .github/workflows/pr-title-validation.yml

Repository: LLM-CR-EVAL/nx-242-cr1

Length of output: 3232


🏁 Script executed:

#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path

workflow = Path(".github/workflows/pr-title-validation.yml").read_text()
start = workflow.index("      - name: Create PR message file")
end = workflow.index("\n      - name: Validate PR title", start)
block = workflow[start:end]
print("--- workflow block ---")
print(block)

# Model GitHub expression interpolation into the run block. The payload is
# data supplied by the pull request, not repository code.
title = 'fix(core): valid $(cat "$GITHUB_WORKSPACE/.git/config")'
body = 'safe\nEOF\nprintf "injected-command-ran\\n"'
generated = block.replace("${{ github.event.pull_request.title }}", title)
generated = generated.replace("${{ github.event.pull_request.body }}", body)
print("--- generated run content ---")
print(generated)

print("--- credential persistence indicators ---")
checkout = workflow[workflow.index("uses: actions/checkout@v4"):workflow.index("\n\n", workflow.index("uses: actions/checkout@v4"))]
print(checkout)
print("persist-credentials explicitly disabled:", "persist-credentials: false" in checkout)
PY

Repository: LLM-CR-EVAL/nx-242-cr1

Length of output: 889


🌐 Web query:

actions/checkout v4 persist-credentials default true local git config official documentation

💡 Result:

In actions/checkout v4, the persist-credentials input defaults to true [1][2][3]. When persist-credentials is set to true (the default), the action configures the authentication token or SSH key to enable authenticated Git commands for subsequent steps in the workflow [1][4]. Official documentation and technical implementation details confirm that this configuration is managed through the local Git configuration [1][2]. Regarding how these credentials are stored: - In actions/checkout v4, the authentication token is persisted directly into the repository's .git/config file [5]. - Note that in later versions (e.g., v6 and beyond), the implementation was improved to store credentials in a separate file within $RUNNER_TEMP, with the .git/config file only containing a pointer to that location [6][7][5]. This change prevents credentials from being included if the workspace directory is uploaded as a build artifact [5]. If you do not require authenticated Git commands in subsequent steps, you can set persist-credentials: false to opt out and prevent the credentials from being written to the configuration [1][5]. Sources: [1] https://github.com/actions/checkout/blob/v4/README.md [2] https://github.com/actions/checkout/blob/v4/action.yml [3] https://github.com/actions/checkout/blob/v4.1.1/action.yml [6] https://github.com/actions/checkout/tree/v6.0.2?tab=readme-ov-file [7] https://github.com/actions/checkout/tree/v6.0.0 [5] cli/go-gh#225

Citations:


Sensitive Data Exposure (CWE-522): Insufficiently Protected Credentials

Reachability: External · Exploitability: Trivial

Disable checkout credential persistence.

The workflow interpolates the pull request title and body into shell commands. An attacker can use this injection to read the token that actions/checkout@v4 stores in .git/config by default. Set persist-credentials: false.

🧰 Tools
🪛 zizmor (1.29.0)

[warning] 15-19: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 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/pr-title-validation.yml around lines 15 - 19, Update the
actions/checkout@v4 step in the workflow to set persist-credentials to false
alongside the existing ref configuration, preventing the checkout action from
storing the repository token in Git configuration.

Source: Linters/SAST tools

Comment on lines +29 to +33
cat > /tmp/pr-message.txt << 'EOF'
${{ github.event.pull_request.title }}

${{ github.event.pull_request.body }}
EOF

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate the title independently of the body.

The supplied scripts/commit-lint.js, Lines 1-83, tests an unanchored regular expression against the entire file. This workflow appends the body at Line 32. An invalid title can pass when the body contains a valid type(scope): subject line. A title with a valid prefix and invalid suffix can also pass.

Write only the title for a title check, or anchor the validator to the complete first line.

🧰 Tools
🪛 zizmor (1.29.0)

[error] 30-30: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 32-32: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 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/pr-title-validation.yml around lines 29 - 33, Update the
pull-request title validation flow around the heredoc writing
/tmp/pr-message.txt so it validates only github.event.pull_request.title,
excluding the pull-request body. Preserve the existing commit-lint.js invocation
while ensuring invalid title suffixes or valid-looking lines in the body cannot
satisfy the title check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants