Skip to content

Upstream Issue Migration via kind/upstream-issue Label #66

@abstractj

Description

@abstractj

Summary

The keycloak-github-bot should automatically migrate issues from keycloak/keycloak-private to keycloak/keycloak when the kind/upstream-issue label is applied. All migrated issues receive the priority/important label regardless of their kind (bug, cve, or enhancement).

Problem Statement

Today, moving issues from the private repository to the public upstream is a manual process assisted by a standalone script based on the status/lift-embargo label. This workflow lives outside the bot. The trigger label name (status/lift-embargo) is also tied to the embargo/CVE workflow and doesn't clearly communicate intent when the migration is for non-security issues that simply belong in the public tracker.

Proposed Solution

Add a new event handler to the keycloak-github-bot that reacts to the kind/upstream-issue label being applied to an issue in keycloak/keycloak-private. The bot should:

  1. Trigger on kind/upstream-issue — when this label is added to an open issue in keycloak/keycloak-private, begin the migration workflow.

  2. Validate before migrating (gates):

    • Abort if the issue has the status/triage label.
    • Abort if the issue has no area/* label.
    • Abort if the issue has more than one of kind/bug, kind/cve, kind/enhancement, or none of them.
    • Abort if the actor who applied kind/upstream-issue is not listed in SECURITY_OWNERS.md.
  3. Create the issue in keycloak/keycloak with:

    • The original title and body (appending a note that it was migrated from the private repository and by whom).
    • The matching kind/* label (kind/bug, kind/cve, or kind/enhancement). From what I'm aware it is not simple to apply the Type though GitHub API, but we can try.
    • All other labels from the source issue that exist in the target repo, except: kind/upstream-issue (trigger) and severity/* labels (not migrated).
  4. Clean up the source issue:

    • Comment on the source issue with a link to the new upstream issue, noting it was moved to the upstream repository.
    • Write a comment to the original reporter providing the link to the issue. For example
    @security reply
    
    The issue is now tracked in the upstream #ISSUEID.
    
    • Close the source issue as duplicate.
    • Remove the kind/upstream-issue label.
    • Lock the source issue with reason "Duplicate".

Value & Benefits

Benefit Who benefits from it Impact
Integrated into the bot Maintainers, security team No standalone scripts to maintain; same reliability and observability as other bot workflows
Clearer trigger semantics Security team, maintainers kind/upstream-issue communicates intent better than status/lift-embargo
Consistent prioritization Triagers, maintainers Every migrated issue gets priority/important, ensuring nothing falls through the cracks
Uniform workflow Security team One label handles bugs, CVEs, and enhancements the same way

User Stories / Scenarios

"As a security team member, I receive a report in keycloak-private that turns out to be a non-security bug. I label it kind/upstream-issue along with kind/bug and the relevant area/* label. The bot creates the issue in keycloak/keycloak with kind/bug, priority/important, and the area labels, then closes and locks the private issue."

"As a maintainer, I identify an enhancement request in the private repo that should be tracked publicly. I add kind/upstream-issue and kind/enhancement. The bot migrates it upstream with priority/important so it gets attention in the next triage cycle."

Flow

flowchart TD
    A["kind/upstream-issue label applied"] --> B{"status/triage present?"}
    B -- Yes --> X1["ABORT: Blocker present"]
    B -- No --> C{"Has area/* label?"}
    C -- No --> X2["ABORT: Missing area label"]
    C -- Yes --> D{"Exactly one kind/* label?"}
    D -- No --> X3["ABORT: Multiple or missing kind labels"]
    D -- Yes --> E{"Issue Type matches kind/* label?"}
    E -- No --> X4["ABORT: Type mismatch"]
    E -- Yes --> F{"Actor authorized?"}
    F -- No --> X5["ABORT: Unauthorized actor"]
    F -- Yes --> G["Create issue in keycloak/keycloak"]
    G --> H["Apply kind/* + priority/important + cloned labels"]
    H --> I["Set Issue Type via GraphQL"]
    I --> J["Comment on source, close as duplicate, remove label, lock"]
Loading

Acceptance Criteria

  • Bot reacts to kind/upstream-issue label being applied in keycloak/keycloak-private
  • All validation gates are enforced (triage blocker, area label, kind exclusivity, type verification, authorization via SECURITY_OWNERS.md)
  • All migrated issues (bug, cve, enhancement) receive priority/important in the target repo
  • Label cloning skips kind/upstream-issue, kind/* (handled explicitly), and severity/*
  • Reporter receives an update with the link to the issue
  • Source issue is commented with a link to the upstream issue, closed as duplicate, trigger label removed, and locked

Out of Scope

  • Changing the source/target repositories
  • Modifying the authorization model (SECURITY_OWNERS.md)
  • Automating the trigger (label is still applied manually by an authorized actor)

Discussion

No response

Motivation

No response

Details

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions