Skip to content

feat: sync linked issue labels to pull requests - #1877

Closed
cheese-cakee wants to merge 26 commits into
hiero-ledger:mainfrom
cheese-cakee:feat/sync-issue-labels
Closed

feat: sync linked issue labels to pull requests#1877
cheese-cakee wants to merge 26 commits into
hiero-ledger:mainfrom
cheese-cakee:feat/sync-issue-labels

Conversation

@cheese-cakee

Copy link
Copy Markdown
Member

Description

Adds an automated GitHub workflow + bot script to sync labels from linked issues to pull requests.

When a PR body includes closing keywords (for example Fixes #123), the workflow fetches labels from those linked issues and adds missing labels to the PR.

Related issue(s)

Fixes #1716

What changed

  • Added compute workflow: .github/workflows/sync-issue-labels-compute.yml
    • Uses pull_request_target on opened, edited, reopened, synchronize, and ready_for_review
    • Includes secure defaults (harden-runner, checkout main, pinned action SHAs)
    • Supports workflow_dispatch with pr_number + dry_run
    • Computes labels from linked issues and uploads as artifact
  • Added add workflow: .github/workflows/sync-issue-labels-add.yml
    • Triggered by workflow_run (not pull_request_target)
    • Uses actions-ecosystem-add-labels action to add labels
    • Runs with write permissions
  • Added script: .github/scripts/sync-issue-labels.js
    • Skips bot/dependabot PRs
    • Parses linked same-repo issue references from closing keywords (fixes/closes/resolves)
    • Aggregates labels from all linked issues (deduplicated)
    • Adds only missing labels to the PR (idempotent/additive)
    • Returns labels for workflow consumption
  • Added changelog entry under [Unreleased] -> .Github

Scope note

This PR intentionally implements label sync only (additive). It does not remove labels from PRs and does not include assignee sync.

Architecture

Two separate workflows to avoid pull_request_target limitations (per exploreriii feedback):

  1. sync-issue-labels-compute.yml - reads labels (runs in pull_request_target context)
  2. sync-issue-labels-add.yml - writes labels (runs in workflow_run context with write permissions)

Testing

  • node --check .github/scripts/sync-issue-labels.js

Checklist

  • Documented (workflow + script behavior is self-logged and changelog updated)
  • Tested (syntax check)

@github-actions

Copy link
Copy Markdown

[commit-verification-bot]
Hi, this is VerificationBot.
Your pull request cannot be merged as it has 1 unverified commit(s):

  • a30af72 feat: sync linked issue labels to pull requests

View your commit verification status: Commits Tab.

To achieve verified status, please read:

Remember, you require a GPG key and each commit must be signed with:
git commit -S -s -m "Your message here"

Thank you for contributing!

From the Hiero Python SDK Team

@cheese-cakee
cheese-cakee force-pushed the feat/sync-issue-labels branch from a30af72 to 1593e8e Compare February 26, 2026 19:19
@coderabbitai

coderabbitai Bot commented Feb 26, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a two-stage GitHub Actions system plus a Node.js script that detect issues linked in a PR body, collect those issues' labels, and apply missing labels to the pull request; includes artifact exchange between workflows, dry-run support, bot/fork safeguards, and a small runner egress allowlist update.

Changes

Cohort / File(s) Summary
Compute Workflow
​.github/workflows/sync-issue-labels-compute.yml
New workflow triggered on PR events and workflow_dispatch: hardens runner, runs sync-issue-labels.js to compute labels, writes labels.json, uploads artifact pr-labels-${PR_NUMBER}, and dispatches the add workflow with upstream run id and inputs.
Add Workflow
​.github/workflows/sync-issue-labels-add.yml
New workflow (workflow_dispatch) that downloads the artifact from the compute run, parses labels.json (no-op if missing), exports outputs, and conditionally adds labels to the PR (respects dry-run, fork PRs, and source_event guards).
Script
​.github/scripts/sync-issue-labels.js
New Node.js action entry script exported via module.exports = async ({ github, context }) => {}: resolves PR context, skips bot-authored PRs, parses closing-references in PR body for issue numbers, fetches each issue (skips PR refs, handles 404), aggregates/normalizes/deduplicates labels, computes delta vs PR labels, logs progress, and applies labels (unless dry-run). Returns labels-to-add for observability.
Changelog
CHANGELOG.md
Updated header formatting and added an Unreleased entry documenting the new workflows and sync script; removed one unrelated doc entry.
Runner Harden config (allowlist)
​.github/workflows/pr-check-test.yml
Allowed-endpoints entry added to Harden the runner step to permit outbound HTTPS to ziply.mm.fcix.net:443.

Sequence Diagram

sequenceDiagram
    actor GitHub as GitHub
    participant ComputeWF as "Compute Workflow"
    participant Script as "sync-issue-labels.js"
    participant API as "GitHub API"
    participant AddWF as "Add Workflow"

    GitHub->>ComputeWF: PR opened/edited/reopened/synchronize or workflow_dispatch
    ComputeWF->>ComputeWF: Harden runner, checkout repo
    ComputeWF->>Script: Run script with PR number & dry_run
    Script->>API: Fetch PR details (if needed)
    Script->>Script: Parse PR body for linked issue numbers
    Script->>API: Fetch each linked issue (skip PR refs, handle 404)
    Script->>Script: Aggregate, normalize, dedupe labels
    Script-->>ComputeWF: Return labels, has_labels, pr_number, dry_run
    ComputeWF->>ComputeWF: Write `labels.json` and upload artifact `pr-labels-${PR_NUMBER}`
    ComputeWF->>GitHub: Dispatch add workflow with artifact run id & inputs
    GitHub->>AddWF: Start Add Workflow
    AddWF->>AddWF: Harden runner, download artifact, read `labels.json`
    AddWF->>API: Apply missing labels to target PR (unless dry-run or fork)
    API-->>AddWF: Confirm labels applied
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: sync linked issue labels to pull requests' directly and clearly summarizes the main change: automating label synchronization from linked issues to PRs.
Description check ✅ Passed The description comprehensively explains the automation added, the workflow trigger events, the script logic for parsing and applying labels, and the related issue. It is clearly related to the changeset.
Linked Issues check ✅ Passed The PR addresses both linked issues: implements security hardening per #123 (harden-runner, pinned actions, least-privileged permissions) and implements label-sync automation per #1716 (parse closing keywords, deduplicate, apply labels).
Out of Scope Changes check ✅ Passed All changes are in scope: two workflows and one script for label sync, a changelog entry, and a minor network endpoint allowlist addition for CI. No extraneous changes detected.

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

📋 Issue Planner

Built with CodeRabbit's Coding Plans for faster development and fewer bugs.

View plan used: #1716

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@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: 4


ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 61a6f38 and a30af72.

📒 Files selected for processing (4)
  • .github/scripts/sync-issue-labels.js
  • .github/workflows/sync-issue-labels-add.yml
  • .github/workflows/sync-issue-labels-compute.yml
  • CHANGELOG.md

Comment thread .github/workflows/sync-issue-labels-add.yml
Comment thread .github/workflows/sync-issue-labels-add.yml Outdated
Comment thread .github/workflows/sync-issue-labels-compute.yml
Comment thread .github/workflows/sync-issue-labels-compute.yml Outdated

@exploreriii exploreriii 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.

@cheese-cakee I appreciate you having another go at this 🥇
Could you please test this on a fork so we see how it does with real github data

@codecov

codecov Bot commented Feb 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #1877   +/-   ##
=======================================
  Coverage   93.54%   93.54%           
=======================================
  Files         141      141           
  Lines        9160     9160           
=======================================
  Hits         8569     8569           
  Misses        591      591           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

Copy link
Copy Markdown

Hi, this is MergeConflictBot.
Your pull request cannot be merged because it contains merge conflicts.

Please resolve these conflicts locally and push the changes.

Quick Fix for CHANGELOG.md Conflicts

If your conflict is only in CHANGELOG.md, you can resolve it easily using the GitHub web editor:

  1. Click on the "Resolve conflicts" button in the PR
  2. Accept both changes (keep both changelog entries)
  3. Click "Mark as resolved"
  4. Commit the merge

For all other merge conflicts, please read:

Thank you for contributing!

@cheese-cakee
cheese-cakee force-pushed the feat/sync-issue-labels branch 2 times, most recently from 9264396 to 89b455d Compare February 27, 2026 22:08
@cheese-cakee

cheese-cakee commented Feb 27, 2026

Copy link
Copy Markdown
Member Author

Hi @exploreriii. The Script Injection warning from Codacy is about the pull_request_target trigger. This trigger is required for this workflow because:

  1. We need to read from main branch (not PR code) for security
  2. We need the PR context to get linked issues from PR body

The workflow already has security measures in place:
ref: main checkout (not PR head - prevents malicious code execution)
harden-runner enabled
Minimal permissions: pull-requests: read, issues: read, contents: read

This is a known trade off for workflows that need to read from main while responding to PR events.
Is there a preferred way to address this, or should we document this exception in the workflow?

@cheese-cakee
cheese-cakee marked this pull request as ready for review March 1, 2026 13:49
Copilot AI review requested due to automatic review settings March 1, 2026 13:49
@cheese-cakee
cheese-cakee requested review from a team and removed request for andrewb1269 and Copilot March 1, 2026 13:49

@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: 5

♻️ Duplicate comments (2)
.github/workflows/sync-issue-labels-compute.yml (1)

62-62: ⚠️ Potential issue | 🔴 Critical

Do not interpolate labels JSON directly into a shell-quoted echo.

Line 62 is vulnerable to quote-breaking/injection if label text contains '. Use a quoted heredoc (or write the file in github-script) instead.

Proposed fix
       - name: Upload labels as artifact
         if: steps.compute.outputs.has_labels == 'true'
         run: |
-          echo '${{ steps.compute.outputs.labels }}' > labels.json
+          cat > labels.json <<'JSON'
+${{ steps.compute.outputs.labels }}
+JSON
         shell: bash

As per coding guidelines, “Treat all GitHub event data as potentially untrusted input… Free-form user input must not flow directly into shell commands…”.

.github/workflows/sync-issue-labels-add.yml (1)

16-16: ⚠️ Potential issue | 🟠 Major

Guard this job when workflow_run.pull_requests is empty.

Line 22 and Line 37 assume pull_requests[0] exists. Because the upstream workflow supports workflow_dispatch, this can be empty and cause runtime failure.

Proposed fix
 jobs:
   add-labels:
-    if: ${{ github.event.workflow_run.conclusion == 'success' }}
+    if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.pull_requests[0] != null }}
     runs-on: ubuntu-latest
For GitHub Actions `workflow_run` events, can `github.event.workflow_run.pull_requests` be empty when the upstream workflow was triggered via `workflow_dispatch`?

Also applies to: 22-23, 37-37


ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a30af72 and a0e10dc.

📒 Files selected for processing (4)
  • .github/scripts/sync-issue-labels.js
  • .github/workflows/sync-issue-labels-add.yml
  • .github/workflows/sync-issue-labels-compute.yml
  • CHANGELOG.md

Comment thread .github/scripts/sync-issue-labels.js Outdated
Comment thread .github/scripts/sync-issue-labels.js
Comment thread .github/workflows/sync-issue-labels-compute.yml Outdated
Comment thread .github/workflows/sync-issue-labels-compute.yml Outdated
Comment thread CHANGELOG.md Outdated
@exploreriii

Copy link
Copy Markdown
Contributor

Did this one get fully tested on a fork for edge cases etc too?

Comment thread .github/workflows/sync-issue-labels-compute.yml Outdated
Comment thread .github/workflows/sync-issue-labels-compute.yml Outdated
Comment thread .github/scripts/sync-issue-labels.js
@cheese-cakee
cheese-cakee marked this pull request as ready for review March 17, 2026 08:08
@cheese-cakee
cheese-cakee force-pushed the feat/sync-issue-labels branch from d52548d to d8d05dd Compare March 17, 2026 08:22
cheese-cakee and others added 26 commits March 17, 2026 19:45
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Co-authored-by: Roger Barker <roger.barker@swirldslabs.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Co-authored-by: Roger Barker <roger.barker@swirldslabs.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Co-authored-by: Roger Barker <roger.barker@swirldslabs.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Co-authored-by: Roger Barker <roger.barker@swirldslabs.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Co-authored-by: Roger Barker <roger.barker@swirldslabs.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Co-authored-by: Roger Barker <roger.barker@swirldslabs.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Co-authored-by: Roger Barker <roger.barker@swirldslabs.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Co-authored-by: Roger Barker <roger.barker@swirldslabs.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Co-authored-by: Roger Barker <roger.barker@swirldslabs.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Co-authored-by: Roger Barker <roger.barker@swirldslabs.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
Signed-off-by: cheese-cakee <farzanaman99@gmail.com>
@cheese-cakee

cheese-cakee commented Mar 17, 2026

Copy link
Copy Markdown
Member Author

Hi @exploreriii @rbarker-dev , I tracked down the current compute workflow failure and fixed it.

Root cause:

  • The compute workflow was checking out github.event.pull_request.head.ref
  • For this PR, that branch exists on my fork, not on hiero-ledger/hiero-sdk-python
  • So the upstream workflow failed trying to fetch a branch that does not exist in the upstream repository

Fix:

  • Changed the compute workflow checkout to checkout the PR branch directly
  • This allows the workflow to find the script file which only exists in the PR

Also applied these surgical fixes from review:

  1. JSON validation in add workflow before applying labels (security)
  2. Fork PRs can now run compute stage (read-only), add stage properly gated

Fork testing:

Test links:

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

Labels

reviewer: maintainer PR needs a review from the maintainer team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Intermediate]: Create a workflow to copy over the issue labels, type to the PR labels

6 participants