Attach OIDC Native to Ingress Resource #3293
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "Cherry-pick dependencies to release branch" | |
| on: | |
| issue_comment: | |
| types: | |
| - created | |
| permissions: | |
| contents: read | |
| jobs: | |
| cherry_pick_to_release: | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| id-token: write | |
| runs-on: ubuntu-24.04 | |
| name: Cherry pick into release branch | |
| if: | | |
| github.repository == 'nginx/kubernetes-ingress' && ( | |
| github.event.issue.pull_request != null && | |
| contains(github.event.comment.body, '/cherry-pick to') && | |
| (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') | |
| ) | |
| steps: | |
| - name: Check PR is merged | |
| id: pr | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | |
| with: | |
| script: | | |
| const pr = await github.rest.pulls.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.issue.number, | |
| }); | |
| if (!pr.data.merged) { | |
| core.setFailed('PR is not merged'); | |
| } | |
| core.setOutput('merge_commit_sha', pr.data.merge_commit_sha); | |
| core.setOutput('body', pr.data.body || ''); | |
| core.setOutput('head_branch', pr.data.head.ref); | |
| core.setOutput('base_ref', pr.data.base.ref); | |
| const commits = await github.rest.pulls.listCommits({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.issue.number, | |
| per_page: 250, | |
| }); | |
| core.setOutput('commit_count', commits.data.length); | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Set release branch variable | |
| id: branch | |
| env: | |
| comment_body: ${{ github.event.comment.body }} | |
| run: | | |
| regex="/cherry-pick to (release-[2-9]+\.[0-9]+|release-20[0-9]{2}-lts)" | |
| if [[ "${comment_body}" =~ $regex ]]; then | |
| branch=${BASH_REMATCH[1]} | |
| if git ls-remote --exit-code --heads origin "${branch}" > /dev/null 2>&1; then | |
| echo "branch=${branch}" >> "$GITHUB_OUTPUT" | |
| fi | |
| fi | |
| - name: Azure login | |
| if: ${{ steps.branch.outputs.branch }} | |
| uses: azure/login@f5d393ae46f8fde4be8b75f32e3fc50e654ad0ca # v3.0.1 | |
| with: | |
| client-id: ${{ secrets.AZURE_COMMON_VAULT_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_COMMON_VAULT_TENANT_ID }} | |
| subscription-id: ${{ secrets.AZURE_COMMON_VAULT_SUBSCRIPTION_ID }} | |
| - name: Get secrets from vault | |
| if: ${{ steps.branch.outputs.branch }} | |
| uses: nginx/ci-self-hosted/.github/actions/get-from-vault@5c3e1f8b51f66a851fdba80f70e19cf966199730 # main @ 2026-05-22 | |
| with: | |
| vault-name: ${{ secrets.COMMON_KEYVAULT_NAME }} | |
| secret-names: "nginx-bot-nic-create-pr-app-client-id, nginx-bot-nic-create-pr-app-private-key" | |
| env-names: "APP_CLIENT_ID, APP_PRIVATE_KEY_B64" | |
| - name: Decode GitHub App private key | |
| id: app_key | |
| if: ${{ steps.branch.outputs.branch }} | |
| run: | | |
| set +x | |
| # Mask the raw base64 value | |
| echo "::add-mask::$APP_PRIVATE_KEY_B64" | |
| private_key=$(printf '%s' "$APP_PRIVATE_KEY_B64" | base64 -d) | |
| # Mask every line of the decoded PEM key individually | |
| while IFS= read -r line; do | |
| if [[ -n "$line" ]]; then | |
| echo "::add-mask::$line" | |
| fi | |
| done <<< "$private_key" | |
| delimiter="GHEOF_$(openssl rand -hex 12)" | |
| { | |
| echo "private_key<<$delimiter" | |
| echo "$private_key" | |
| echo "$delimiter" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Generate GitHub App token | |
| id: app_token | |
| if: ${{ steps.branch.outputs.branch }} | |
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 | |
| with: | |
| client-id: ${{ env.APP_CLIENT_ID }} | |
| private-key: ${{ steps.app_key.outputs.private_key }} | |
| owner: ${{ github.repository_owner }} | |
| repositories: ${{ github.event.repository.name }} | |
| - name: Check if actor is authorized for cherry-pick | |
| if: ${{ steps.branch.outputs.branch }} | |
| run: | | |
| IFS=',' read -ra AUTHORIZED_USERS <<< "${{ vars.CHERRY_PICK_USERS }}" | |
| for user in "${AUTHORIZED_USERS[@]}"; do | |
| user=$(echo "$user" | xargs) # trim whitespace | |
| if [[ "$user" == "${{ github.actor }}" ]]; then | |
| echo "Actor ${{ github.actor }} is authorized" | |
| exit 0 | |
| fi | |
| done | |
| echo "::error::Actor ${{ github.actor }} is not authorized for cherry-pick" | |
| exit 1 | |
| - name: Cherry pick into ${{ steps.branch.outputs.branch }} | |
| if: ${{ steps.branch.outputs.branch }} | |
| env: | |
| GH_TOKEN: ${{ steps.app_token.outputs.token }} | |
| TARGET_BRANCH: ${{ steps.branch.outputs.branch }} | |
| MERGE_SHA: ${{ steps.pr.outputs.merge_commit_sha }} | |
| PR_TITLE: ${{ github.event.issue.title }} | |
| PR_BODY: ${{ steps.pr.outputs.body }} | |
| HEAD_BRANCH: ${{ steps.pr.outputs.head_branch }} | |
| BASE_REF: ${{ steps.pr.outputs.base_ref }} | |
| PR_COMMIT_COUNT: ${{ steps.pr.outputs.commit_count }} | |
| run: | | |
| git config user.name "${{ github.actor }}" | |
| git config user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com" | |
| git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" | |
| PREFIX=$(echo "${HEAD_BRANCH}" | grep -oE '^[a-z]+/' || echo '') | |
| CHERRY_BRANCH="${PREFIX}cherry-pick-${TARGET_BRANCH}-${MERGE_SHA}" | |
| git checkout -b "${CHERRY_BRANCH}" "origin/${TARGET_BRANCH}" | |
| # Detect merge strategy from the commit's parent count and apply | |
| # the correct cherry-pick invocation: | |
| # 2+ parents → merge commit → cherry-pick -m 1 | |
| # 1 parent on base → squash → cherry-pick directly | |
| # 1 parent NOT on base → rebase → cherry-pick full range | |
| PARENT_COUNT=$(git cat-file -p "${MERGE_SHA}" | grep -c '^parent ') | |
| if [ "${PARENT_COUNT}" -ge 2 ]; then | |
| echo "Detected merge commit — using -m 1" | |
| git cherry-pick -x -m 1 "${MERGE_SHA}" | |
| elif git merge-base --is-ancestor "${MERGE_SHA}^" "origin/${BASE_REF}" 2>/dev/null; then | |
| echo "Detected squash merge (or single-commit rebase)" | |
| git cherry-pick -x "${MERGE_SHA}" | |
| else | |
| echo "Detected rebase merge with ${PR_COMMIT_COUNT} commit(s)" | |
| git cherry-pick -x "${MERGE_SHA}~${PR_COMMIT_COUNT}..${MERGE_SHA}" | |
| fi | |
| # Push the branch, force-updating if a previous run already created it | |
| if git ls-remote --exit-code --heads origin "${CHERRY_BRANCH}" > /dev/null 2>&1; then | |
| git fetch origin "${CHERRY_BRANCH}" | |
| git push --force-with-lease origin "${CHERRY_BRANCH}" | |
| else | |
| git push origin "${CHERRY_BRANCH}" | |
| fi | |
| # Create a PR only if one doesn't already exist for this branch | |
| EXISTING_PR=$(gh pr list \ | |
| --head "${CHERRY_BRANCH}" \ | |
| --base "${TARGET_BRANCH}" \ | |
| --state open \ | |
| --json url \ | |
| --jq '.[0].url // empty') | |
| if [ -n "${EXISTING_PR}" ]; then | |
| echo "Cherry-pick PR already exists: ${EXISTING_PR}" | |
| else | |
| gh pr create \ | |
| --title "[cherry-pick to ${TARGET_BRANCH}] ${PR_TITLE}" \ | |
| --body "${PR_BODY}" \ | |
| --base "${TARGET_BRANCH}" \ | |
| --head "${CHERRY_BRANCH}" | |
| fi |