Skip to content

Add use-pr-linker workflow to auto-link PRs to issues#279

Open
Ivanmeneges wants to merge 1 commit into
develop-java21from
add/use-pr-linker-workflow-develop-java21
Open

Add use-pr-linker workflow to auto-link PRs to issues#279
Ivanmeneges wants to merge 1 commit into
develop-java21from
add/use-pr-linker-workflow-develop-java21

Conversation

@Ivanmeneges

@Ivanmeneges Ivanmeneges commented May 25, 2026

Copy link
Copy Markdown

Summary

Adds use-pr-linker.yml workflow that calls the reusable PR-to-issue linker from mosip/kattu (@develop).

Notes

  • Requires ACTION_PAT repository secret to be configured.
  • Target branch: develop-java21.

Summary by CodeRabbit

  • Chores
    • Added automated linking of pull requests to related issues, improving project tracking and management.

@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

This PR adds a GitHub Actions workflow that automatically links pull requests to related issues. The workflow triggers on pull_request_target events, configures minimal required permissions, and delegates the linking logic to an external shared workflow from the mosip/kattu repository.

Changes

PR-to-Issue Linking Automation

Layer / File(s) Summary
PR-to-issue linking workflow configuration
.github/workflows/use-pr-linker.yml
New workflow triggered on pull_request_target events (opened, edited, synchronize, reopened, closed) configures read permissions for contents and pull-requests, write permission for issues, and calls the external mosip/kattu/.github/workflows/link-pr-to-issue.yml@develop workflow via the call-linker job, passing the ACTION_PAT secret.

Estimated Code Review Effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

🐰 A workflow so neat, a job quite divine,
Links PR to issues, makes workflow align,
With kattu borrowed wisdom so fine,
Automation flows smoothly through the design! 🔗

🚥 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 PR title accurately describes the main change: adding a GitHub Actions workflow that auto-links PRs to issues.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add/use-pr-linker-workflow-develop-java21

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@Ivanmeneges Ivanmeneges force-pushed the add/use-pr-linker-workflow-develop-java21 branch from 1c00bbc to 37dcf13 Compare May 25, 2026 11:17
Signed-off-by: Ivanmeneges <ivan.anil016@gmail.com>
@Ivanmeneges Ivanmeneges force-pushed the add/use-pr-linker-workflow-develop-java21 branch from 37dcf13 to 11e0cbf Compare May 31, 2026 10:16

@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: 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/use-pr-linker.yml:
- Around line 19-21: Replace the mutable ref in the reusable workflow call so
the "uses: mosip/kattu/.github/workflows/link-pr-to-issue.yml@develop" line pins
to an immutable commit SHA (e.g., replace "`@develop`" with the specific commit
SHA like "`@6bb3c38b8f5643b906a0d7f4baaede996766b71e`") to prevent remote changes
from getting executed with the injected secret ACTION_PAT; ensure the "secrets:
ACTION_PAT" mapping is left intact after updating the ref.
- Around line 3-10: The workflow exposes secrets to untrusted forks because it
uses pull_request_target and forwards secrets.ACTION_PAT to the external mutable
workflow mosip/kattu/.github/workflows/link-pr-to-issue.yml@develop (used as
GH_TOKEN) while deriving REPO/NUMBER from PR title/body; to fix, change the
trigger from pull_request_target to pull_request if you don't need elevated
permissions for fork PRs, otherwise stop passing ACTION_PAT to mutable external
workflows and instead pin the called workflow to a commit SHA (or vendor its
steps), add a guard that verifies github.event.pull_request.base.repo.full_name
=== github.repository (i.e., only same-repo PRs) before exposing secrets and
restrict permissions to the minimum necessary (avoid issues: write or remove
destructive scopes), and validate/whitelist the derived REPO/NUMBER so comments
can only target the base repo.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2c78847b-e420-45d3-bc09-f4609fb69f64

📥 Commits

Reviewing files that changed from the base of the PR and between 6fd7c30 and 11e0cbf.

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

Comment on lines +3 to +10
on:
pull_request_target:
types:
- opened
- edited
- synchronize
- reopened
- closed

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 | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Fetch and examine the external workflow to understand its permissions requirements
curl -s https://raw.githubusercontent.com/mosip/kattu/develop/.github/workflows/link-pr-to-issue.yml | head -50

Repository: mosip/audit-manager

Length of output: 1283


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Inspect local workflow
echo "== Local: .github/workflows/use-pr-linker.yml =="
nl -ba .github/workflows/use-pr-linker.yml | sed -n '1,200p'

echo
echo "== Local: search for secret/ref passing =="
rg -n "mosip/kattu|ACTION_PAT|workflow_call|uses:" .github/workflows/use-pr-linker.yml || true

# 2) Inspect external workflow more thoroughly
URL="https://raw.githubusercontent.com/mosip/kattu/develop/.github/workflows/link-pr-to-issue.yml"

echo
echo "== External: head (first 220 lines) =="
curl -s "$URL" | nl -ba | sed -n '1,220p'

echo
echo "== External: grep for ACTION_PAT usage and fork-related checks =="
curl -s "$URL" | rg -n "ACTION_PAT|secrets\.ACTION_PAT|fork|fromFork|pull_request\.head|head_repo|repository_owner|is_fork|base_repo|permissions" || true

echo
echo "== External: tail (last 220 lines) =="
curl -s "$URL" | nl -ba | tail -n 220

Repository: mosip/audit-manager

Length of output: 173


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Local: .github/workflows/use-pr-linker.yml =="
cat -n .github/workflows/use-pr-linker.yml | sed -n '1,220p'

echo
echo "== Local: search for uses/ref + secret passing =="
rg -n "mosip/kattu|ACTION_PAT|workflow_call|secrets:|secrets\.ACTION_PAT|uses:" .github/workflows/use-pr-linker.yml || true

echo
echo "== External: full text is unknown size; search by patterns =="
URL="https://raw.githubusercontent.com/mosip/kattu/develop/.github/workflows/link-pr-to-issue.yml"
curl -s "$URL" > /tmp/link-pr-to-issue.yml

echo
echo "== External: occurrences =="
rg -n "ACTION_PAT|secrets\.ACTION_PAT|fork|fromFork|is_fork|head_repo|head.*repo|pull_request\.head|repository_owner|base_repo|permissions" /tmp/link-pr-to-issue.yml || true

echo
echo "== External: show lines around ACTION_PAT usage =="
rg -n "ACTION_PAT|secrets\.ACTION_PAT" -n /tmp/link-pr-to-issue.yml | head -n 50 || true
# Print a context window around first 3 matches (if any)
python3 - <<'PY'
import re
path="/tmp/link-pr-to-issue.yml"
with open(path,'r',encoding='utf-8') as f:
    lines=f.readlines()
idx=[]
for i,l in enumerate(lines, start=1):
    if "ACTION_PAT" in l:
        idx.append(i)
for i in idx[:3]:
    start=max(1,i-25); end=min(len(lines), i+40)
    print(f"\n--- {path}: lines {start}-{end} (match at {i}) ---")
    for j in range(start, end+1):
        print(f"{j}\t{lines[j-1].rstrip()}")
PY

Repository: mosip/audit-manager

Length of output: 7471


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Local: file length =="
wc -l .github/workflows/use-pr-linker.yml

echo
echo "== Local: full file =="
cat -n .github/workflows/use-pr-linker.yml

echo
echo "== External: look for any fork/untrusted checks =="
curl -s "https://raw.githubusercontent.com/mosip/kattu/develop/.github/workflows/link-pr-to-issue.yml" > /tmp/link-pr-to-issue.yml
rg -n "fork|fromFork|is_fork|head_repo|head\.repo|pull_request\.head|repository_owner|base_repo" /tmp/link-pr-to-issue.yml || true

echo
echo "== External: where GH_TOKEN is used (context) =="
rg -n "GH_TOKEN: \$\{\{ secrets\.ACTION_PAT \}\}|Authorization: Bearer \$GH_TOKEN|issues/comments|api.github.com/search/issues|curl -s -X (POST|PUT|PATCH)|curl -s -X DELETE" /tmp/link-pr-to-issue.yml

echo
echo "== External: show around first POST/PUT/PATCH (if any) =="
python3 - <<'PY'
import re
path="/tmp/link-pr-to-issue.yml"
with open(path,'r',encoding='utf-8') as f: lines=f.readlines()
targets=[]
for i,l in enumerate(lines, start=1):
    if re.search(r'curl -s -X (POST|PUT|PATCH)', l):
        targets.append(i)
for i in targets[:5]:
    s=max(1,i-20); e=min(len(lines), i+25)
    print(f"\n--- {path}: lines {s}-{e} (match at {i}) ---")
    for j in range(s,e+1):
        print(f"{j}\t{lines[j-1].rstrip()}")
PY

Repository: mosip/audit-manager

Length of output: 1124


🏁 Script executed:

#!/bin/bash
set -euo pipefail

URL="https://raw.githubusercontent.com/mosip/kattu/develop/.github/workflows/link-pr-to-issue.yml"
curl -s "$URL" > /tmp/link-pr-to-issue.yml

echo "== External: check for any fork/untrusted gating patterns =="
rg -n "fork|fromFork|is_fork|head\.repo|base\.repo|repository_owner|event\.pull_request\.head" /tmp/link-pr-to-issue.yml || true

echo
echo "== External: locate comment creation / POST usage =="
rg -n "curl -s -X POST|issues/comments" /tmp/link-pr-to-issue.yml || true

echo
python3 - <<'PY'
import re
path="/tmp/link-pr-to-issue.yml"
lines=open(path,'r',encoding='utf-8').read().splitlines()
# find likely comment/PR-link marker logic
patterns=["MARKER=","pr-linker:","pr-linker:","<!-- pr-linker:","issues/comments","COMMENT_ID","SOURCE_REPO","ISSUE_REPO","REPO="]
for p in patterns:
    hits=[i+1 for i,l in enumerate(lines) if p in l]
    if hits:
        print(f"\n-- first hits for {p} at lines {hits[:5]} --")
        i=hits[0]
        s=max(1,i-35); e=min(len(lines), i+70)
        for j in range(s,e+1):
            print(f"{j}\t{lines[j-1]}")
PY

Repository: mosip/audit-manager

Length of output: 36974


🏁 Script executed:

#!/bin/bash
set -euo pipefail

URL="https://raw.githubusercontent.com/mosip/kattu/develop/.github/workflows/link-pr-to-issue.yml"
curl -s "$URL" > /tmp/link-pr-to-issue.yml

echo "== External: search for any POST (including multiline -X POST) and comment creation =="
rg -n "curl -s.*-X\s*POST|X POST|issues/.*/comments\?per_page|issues/\$NUMBER/comments" /tmp/link-pr-to-issue.yml || true

echo
echo "== External: show section around where it likely posts comment (first match on issues/$NUMBER/comments without -X DELETE) =="
python3 - <<'PY'
import re
path="/tmp/link-pr-to-issue.yml"
lines=open(path,'r',encoding='utf-8').read().splitlines()
# find first occurrence of "issues/$NUMBER/comments" and show nearby lines
for i,l in enumerate(lines):
    if "issues/$NUMBER/comments" in l and "-X DELETE" not in l:
        start=max(0,i-40); end=min(len(lines)-1,i+80)
        print(f"--- lines {start+1}-{end+1} around first non-delete use at {i+1} ---")
        for j in range(start,end+1):
            print(f"{j+1}\t{lines[j]}")
        break
PY

echo
echo "== External: check for any explicit fork/untrusted checks around PR events =="
rg -n "fork|fromFork|is_fork|head_repo|base_repo|repository_owner|pull_request\.head|security|untrusted|trusted" /tmp/link-pr-to-issue.yml || true

Repository: mosip/audit-manager

Length of output: 394


🏁 Script executed:

#!/bin/bash
set -euo pipefail

URL="https://raw.githubusercontent.com/mosip/kattu/develop/.github/workflows/link-pr-to-issue.yml"
curl -s "$URL" > /tmp/link-pr-to-issue.yml

echo "== External: grep for POST usage (comment creation) =="
rg -n "curl\s+-s\s+-w.*-X\s+POST|curl.*-X\s+POST|issues/comments\?" /tmp/link-pr-to-issue.yml || true

echo
echo "== External: show around CREATE_RESPONSE (-X POST) =="
python3 - <<'PY'
import re
path="/tmp/link-pr-to-issue.yml"
lines=open(path,'r',encoding='utf-8').read().splitlines()
create=[]
for i,l in enumerate(lines, start=1):
    if "CREATE_RESPONSE" in l or "-X POST" in l:
        create.append(i)
print("matches:", create[:10])
start_line = create[0] if create else None
if start_line:
    s=max(1,start_line-80); e=min(len(lines), start_line+120)
    for j in range(s,e+1):
        print(f"{j}\t{lines[j-1]}")
PY

echo
echo "== External: search for any fork/untrusted gating =="
rg -n "fork|fromFork|is_fork|head_repo|base_repo|repository_owner|pull_request\.head|security|untrusted|trusted" /tmp/link-pr-to-issue.yml || true

echo
echo "== External: search for any validation of issue targets from PR body =="
rg -n "grep -Eo '([a-zA-Z0-9_.-]+/|cut -d'#'|ISSUES=|ISSUE_COUNT|SOURCE_REPO|REPO=\" /tmp/link-pr-to-issue.yml || true

Repository: mosip/audit-manager

Length of output: 4638


🏁 Script executed:

#!/bin/bash
set -euo pipefail

URL="https://raw.githubusercontent.com/mosip/kattu/develop/.github/workflows/link-pr-to-issue.yml"
curl -s "$URL" > /tmp/link-pr-to-issue.yml

python3 - <<'PY'
import re
path="/tmp/link-pr-to-issue.yml"
lines=open(path,'r',encoding='utf-8').read().splitlines()

def show_around(needle, radius=60, max_print=220):
    for i,l in enumerate(lines):
        if needle in l:
            s=max(0,i-radius); e=min(len(lines)-1,i+radius)
            print(f"\n--- around '{needle}' (lines {s+1}-{e+1}) ---")
            for j in range(s,e+1):
                print(f"{j+1}\t{lines[j]}")
            return True
    return False

needles=[
    "ISSUES=$(echo \"$BODY\"",
    "grep -Eo '([a-zA-Z0-9_.-]+\\/[a-zA-Z0-9_.-]+)?#[0-9]+'",
    "if [[ \"$ISSUE\" == *\"/\"* ]]; then",
    "REPO=\"$SOURCE_REPO\"",
    "Processing $REPO#$NUMBER",
]
for n in needles:
    ok=show_around(n, radius=55)
    if not ok:
        print(f"\n--- needle not found: {n} ---")
PY

echo "== External: grep for any comparisons between REPO and SOURCE_REPO =="
rg -n "REPO.*SOURCE_REPO|SOURCE_REPO.*REPO|if.*REPO|allow|whitelist" /tmp/link-pr-to-issue.yml || true

Repository: mosip/audit-manager

Length of output: 19811


Major security risk: pull_request_target passing ACTION_PAT to mutable external workflow enables fork-driven issue/comment writes.

  • .github/workflows/use-pr-linker.yml runs on pull_request_target and passes secrets.ACTION_PAT into mosip/kattu/.github/workflows/link-pr-to-issue.yml@develop (mutable ref), with issues: write permissions.
  • The called workflow requires secrets.ACTION_PAT and uses it as GH_TOKEN to search, delete, PATCH, and POST issue comments via the GitHub API.
  • It derives the target REPO/NUMBER from PR title/body: it accepts owner/repo#number (or defaults to the base repo) and then uses https://api.github.com/repos/$REPO/issues/$NUMBER/comments...—there’s no fork/untrusted-source gating shown before using the PAT.

Verify whether pull_request_target is necessary for fork PRs; if not, switch to pull_request. If it must remain, gate secret usage to same-repo PRs only, pin the external workflow to a commit SHA (or vendor it), and restrict comment targets to the base repo.

🧰 Tools
🪛 zizmor (1.25.2)

[error] 3-10: 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/use-pr-linker.yml around lines 3 - 10, The workflow
exposes secrets to untrusted forks because it uses pull_request_target and
forwards secrets.ACTION_PAT to the external mutable workflow
mosip/kattu/.github/workflows/link-pr-to-issue.yml@develop (used as GH_TOKEN)
while deriving REPO/NUMBER from PR title/body; to fix, change the trigger from
pull_request_target to pull_request if you don't need elevated permissions for
fork PRs, otherwise stop passing ACTION_PAT to mutable external workflows and
instead pin the called workflow to a commit SHA (or vendor its steps), add a
guard that verifies github.event.pull_request.base.repo.full_name ===
github.repository (i.e., only same-repo PRs) before exposing secrets and
restrict permissions to the minimum necessary (avoid issues: write or remove
destructive scopes), and validate/whitelist the derived REPO/NUMBER so comments
can only target the base repo.

Comment on lines +19 to +21
uses: mosip/kattu/.github/workflows/link-pr-to-issue.yml@develop
secrets:
ACTION_PAT: ${{ secrets.ACTION_PAT }} No newline at end of file

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 | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Fetch the latest commit SHA for the develop branch of mosip/kattu
curl -s https://api.github.com/repos/mosip/kattu/commits/develop | jq -r '.sha'

Repository: mosip/audit-manager

Length of output: 104


Critical: Pin reusable workflow to an immutable commit SHA instead of @develop.

This workflow runs on pull_request_target and passes secrets.ACTION_PAT to mosip/kattu/.github/workflows/link-pr-to-issue.yml@develop; using a mutable ref allows the called workflow to change and potentially exfiltrate/abuse the secret. Pin it to a commit SHA (e.g., 6bb3c38b8f5643b906a0d7f4baaede996766b71e).

🔒 Proposed fix
 jobs:
   call-linker:
-    uses: mosip/kattu/.github/workflows/link-pr-to-issue.yml@develop
+    uses: mosip/kattu/.github/workflows/link-pr-to-issue.yml@6bb3c38b8f5643b906a0d7f4baaede996766b71e
     secrets:
       ACTION_PAT: ${{ secrets.ACTION_PAT }}
📝 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
uses: mosip/kattu/.github/workflows/link-pr-to-issue.yml@develop
secrets:
ACTION_PAT: ${{ secrets.ACTION_PAT }}
uses: mosip/kattu/.github/workflows/link-pr-to-issue.yml@6bb3c38b8f5643b906a0d7f4baaede996766b71e
secrets:
ACTION_PAT: ${{ secrets.ACTION_PAT }}
🧰 Tools
🪛 zizmor (1.25.2)

[error] 19-19: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 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/use-pr-linker.yml around lines 19 - 21, Replace the
mutable ref in the reusable workflow call so the "uses:
mosip/kattu/.github/workflows/link-pr-to-issue.yml@develop" line pins to an
immutable commit SHA (e.g., replace "`@develop`" with the specific commit SHA like
"`@6bb3c38b8f5643b906a0d7f4baaede996766b71e`") to prevent remote changes from
getting executed with the injected secret ACTION_PAT; ensure the "secrets:
ACTION_PAT" mapping is left intact after updating the ref.

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.

1 participant