From 08e6b44a4d85d29098dd5ed22576a353258b9599 Mon Sep 17 00:00:00 2001 From: ilhan007 Date: Thu, 28 May 2026 15:24:47 +0300 Subject: [PATCH 1/3] ci(release): use short-lived GitHub App token instead of long-lived PAT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace every `secrets.UI5_WEBCOMP_BOT_GH_TOKEN` usage in the release workflow with a per-run installation token generated by `actions/create-github-app-token@v2`. App tokens are valid for ~1 hour and disappear when the run ends, drastically reducing the blast radius compared to a long-lived PAT. Aligns release.yaml with OSPO Guideline #4 ("Replace long-lived secrets with OIDC"). The same PAT is still consumed by deploy-preview.yaml, reset-preview-deploy.yaml, reset-gh-pages.yaml and issue-monthly-report.yaml; those workflows are intentionally out of scope and will be migrated in follow-up PRs. Requires (one-time, before merge): - Register a GitHub App with Contents/Issues/Pull-requests: write - Install it on SAP/ui5-webcomponents - Add it to the branch-protection bypass list for release branches - Add repo secrets RELEASE_BOT_APP_ID and RELEASE_BOT_APP_PRIVATE_KEY The npm publish flow already uses OIDC (id-token: write, no NPM_TOKEN); no changes there. UI5_WEBCOMP_BOT_NAME / _EMAIL are kept as-is — they are git identity strings, not credentials. --- .github/workflows/release.yaml | 81 +++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 22 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a1883c5c5f17..4a34ea31565f 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -37,10 +37,17 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: + - name: Generate App Token + id: app-token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ secrets.RELEASE_BOT_APP_ID }} + private-key: ${{ secrets.RELEASE_BOT_APP_PRIVATE_KEY }} + - name: Checkout uses: actions/checkout@v4 with: - token: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + token: ${{ steps.app-token.outputs.token }} fetch-depth: 0 - name: Setup Node @@ -54,7 +61,7 @@ jobs: - name: Version Bump env: - GH_TOKEN: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | git config user.name "${{ secrets.UI5_WEBCOMP_BOT_NAME }}" git config user.email "${{ secrets.UI5_WEBCOMP_BOT_EMAIL }}" @@ -76,9 +83,9 @@ jobs: - name: Create GitHub Release uses: actions/github-script@v7 env: - GH_TOKEN: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} with: - github-token: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + github-token: ${{ steps.app-token.outputs.token }} script: | const extractChangelog = (await import('${{ github.workspace }}/.github/actions/extractChangelog.mjs')).default; const changelog = await extractChangelog(); @@ -98,9 +105,9 @@ jobs: - name: Merge Release Changelog uses: actions/github-script@v7 env: - GH_TOKEN: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} with: - github-token: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + github-token: ${{ steps.app-token.outputs.token }} script: | const mergeReleaseChangelog = (await import('${{ github.workspace }}/.github/actions/mergeReleaseChangelog.mjs')).default; await mergeReleaseChangelog({ github , context }); @@ -109,9 +116,9 @@ jobs: uses: actions/github-script@v7 env: NODE_OPTIONS: '--max-old-space-size=12096' - GH_TOKEN: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} with: - github-token: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + github-token: ${{ steps.app-token.outputs.token }} script: | const commentOnFixedIssues = (await import('${{ github.workspace }}/.github/actions/commentOnFixedIssues.mjs')).default; await commentOnFixedIssues({ github, context }); @@ -125,6 +132,7 @@ jobs: - name: Deploy uses: JamesIves/github-pages-deploy-action@v4.3.3 with: + token: ${{ steps.app-token.outputs.token }} branch: gh-pages # The branch the action should deploy to. folder: packages/website/build # The folder the action should deploy. clean: true @@ -145,10 +153,17 @@ jobs: pages: write runs-on: ubuntu-latest steps: + - name: Generate App Token + id: app-token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ secrets.RELEASE_BOT_APP_ID }} + private-key: ${{ secrets.RELEASE_BOT_APP_PRIVATE_KEY }} + - name: Checkout uses: actions/checkout@v4 with: - token: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + token: ${{ steps.app-token.outputs.token }} fetch-depth: 0 - name: Setup Node @@ -162,7 +177,7 @@ jobs: - name: Version Bump env: - GH_TOKEN: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | git config user.name "${{ secrets.UI5_WEBCOMP_BOT_NAME }}" git config user.email "${{ secrets.UI5_WEBCOMP_BOT_EMAIL }}" @@ -193,9 +208,9 @@ jobs: - name: Create GitHub Release uses: actions/github-script@v7 env: - GH_TOKEN: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} with: - github-token: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + github-token: ${{ steps.app-token.outputs.token }} script: | const extractChangelog = (await import('${{ github.workspace }}/.github/actions/extractChangelog.mjs')).default; const changelog = await extractChangelog(); @@ -220,6 +235,7 @@ jobs: - name: Deploy to GitHub Pages uses: JamesIves/github-pages-deploy-action@v4.3.3 with: + token: ${{ steps.app-token.outputs.token }} branch: gh-pages folder: packages/website/build target-folder: nightly @@ -229,9 +245,9 @@ jobs: uses: actions/github-script@v7 env: NODE_OPTIONS: '--max-old-space-size=12096' - GH_TOKEN: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} with: - github-token: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + github-token: ${{ steps.app-token.outputs.token }} script: | const commentOnFixedIssues = (await import('${{ github.workspace }}/.github/actions/commentOnFixedIssues.mjs')).default; await commentOnFixedIssues({ github, context }); @@ -247,10 +263,17 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: + - name: Generate App Token + id: app-token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ secrets.RELEASE_BOT_APP_ID }} + private-key: ${{ secrets.RELEASE_BOT_APP_PRIVATE_KEY }} + - name: Checkout uses: actions/checkout@v4 with: - token: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + token: ${{ steps.app-token.outputs.token }} fetch-depth: 0 - name: Setup Node @@ -264,7 +287,7 @@ jobs: - name: Version Bump env: - GH_TOKEN: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | git config user.name "${{ secrets.UI5_WEBCOMP_BOT_NAME }}" git config user.email "${{ secrets.UI5_WEBCOMP_BOT_EMAIL }}" @@ -286,9 +309,9 @@ jobs: - name: Create GitHub Release uses: actions/github-script@v7 env: - GH_TOKEN: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} with: - github-token: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + github-token: ${{ steps.app-token.outputs.token }} script: | const extractChangelog = (await import('${{ github.workspace }}/.github/actions/extractChangelog.mjs')).default; const changelog = await extractChangelog(); @@ -316,10 +339,17 @@ jobs: id-token: write runs-on: ubuntu-latest steps: + - name: Generate App Token + id: app-token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ secrets.RELEASE_BOT_APP_ID }} + private-key: ${{ secrets.RELEASE_BOT_APP_PRIVATE_KEY }} + - name: Checkout uses: actions/checkout@v4 with: - token: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + token: ${{ steps.app-token.outputs.token }} fetch-depth: 0 - name: Setup Node @@ -333,7 +363,7 @@ jobs: - name: Version Bump env: - GH_TOKEN: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | git config user.name "${{ secrets.UI5_WEBCOMP_BOT_NAME }}" git config user.email "${{ secrets.UI5_WEBCOMP_BOT_EMAIL }}" @@ -363,10 +393,17 @@ jobs: id-token: write runs-on: ubuntu-latest steps: + - name: Generate App Token + id: app-token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ secrets.RELEASE_BOT_APP_ID }} + private-key: ${{ secrets.RELEASE_BOT_APP_PRIVATE_KEY }} + - name: Checkout uses: actions/checkout@v4 with: - token: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + token: ${{ steps.app-token.outputs.token }} fetch-depth: 0 - name: Setup Node @@ -380,7 +417,7 @@ jobs: - name: Version Bump env: - GH_TOKEN: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | git config user.name "${{ secrets.UI5_WEBCOMP_BOT_NAME }}" git config user.email "${{ secrets.UI5_WEBCOMP_BOT_EMAIL }}" From 3b9a0aa0ce67d7199f4958cedf2f4ea4c8a824fe Mon Sep 17 00:00:00 2001 From: ilhan007 Date: Tue, 2 Jun 2026 17:56:43 +0300 Subject: [PATCH 2/3] ci(release): pin create-github-app-token to v3.2.0 SHA, drop BOT prefix from secret names Addresses review feedback on #13604: - pin actions/create-github-app-token to v3.2.0 commit SHA per GitHub third-party action security guidance (tags can be moved, SHAs cannot) - v3 is safe for us: breaking changes are Node 24 (we use ubuntu-latest hosted runners which support it) and removed custom proxy handling (we do not use proxies) - rename RELEASE_BOT_APP_ID / RELEASE_BOT_APP_PRIVATE_KEY to RELEASE_APP_ID / RELEASE_APP_PRIVATE_KEY to match repo secret names --- .github/workflows/release.yaml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4a34ea31565f..f185fb5434d0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -39,10 +39,10 @@ jobs: steps: - name: Generate App Token id: app-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: - app-id: ${{ secrets.RELEASE_BOT_APP_ID }} - private-key: ${{ secrets.RELEASE_BOT_APP_PRIVATE_KEY }} + app-id: ${{ secrets.RELEASE_APP_ID }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - name: Checkout uses: actions/checkout@v4 @@ -155,10 +155,10 @@ jobs: steps: - name: Generate App Token id: app-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: - app-id: ${{ secrets.RELEASE_BOT_APP_ID }} - private-key: ${{ secrets.RELEASE_BOT_APP_PRIVATE_KEY }} + app-id: ${{ secrets.RELEASE_APP_ID }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - name: Checkout uses: actions/checkout@v4 @@ -265,10 +265,10 @@ jobs: steps: - name: Generate App Token id: app-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: - app-id: ${{ secrets.RELEASE_BOT_APP_ID }} - private-key: ${{ secrets.RELEASE_BOT_APP_PRIVATE_KEY }} + app-id: ${{ secrets.RELEASE_APP_ID }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - name: Checkout uses: actions/checkout@v4 @@ -341,10 +341,10 @@ jobs: steps: - name: Generate App Token id: app-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: - app-id: ${{ secrets.RELEASE_BOT_APP_ID }} - private-key: ${{ secrets.RELEASE_BOT_APP_PRIVATE_KEY }} + app-id: ${{ secrets.RELEASE_APP_ID }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - name: Checkout uses: actions/checkout@v4 @@ -395,10 +395,10 @@ jobs: steps: - name: Generate App Token id: app-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: - app-id: ${{ secrets.RELEASE_BOT_APP_ID }} - private-key: ${{ secrets.RELEASE_BOT_APP_PRIVATE_KEY }} + app-id: ${{ secrets.RELEASE_APP_ID }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - name: Checkout uses: actions/checkout@v4 From b9e310ade8bfbba126feb92776057d7e2c6b9a97 Mon Sep 17 00:00:00 2001 From: ilhan007 Date: Tue, 2 Jun 2026 18:12:24 +0300 Subject: [PATCH 3/3] ci(release): keep GITHUB_TOKEN for experimental, drop App-token step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves the merge conflict between this PR and main introduced by 49bade48d ("swap PAT for GITHUB_TOKEN in experimental-release job"). experimental-release does not push tags or branches, does not create a GitHub release, and does not need elevated privileges — GITHUB_TOKEN is sufficient. Removes the now-unused 'Generate App Token' step from this job and reverts contents permission from write back to read. App tokens remain in stable/rc/hotfix/v1 jobs where they're needed for tag pushes against branch-protected refs. --- .github/workflows/release.yaml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index f185fb5434d0..0839ff6427e9 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -335,21 +335,14 @@ jobs: if: ${{ github.event.inputs.release_type == 'experimental' }} environment: "npmjs:@ui5/webcomponents" permissions: - contents: write + contents: read id-token: write runs-on: ubuntu-latest steps: - - name: Generate App Token - id: app-token - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 - with: - app-id: ${{ secrets.RELEASE_APP_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - - name: Checkout uses: actions/checkout@v4 with: - token: ${{ steps.app-token.outputs.token }} + token: ${{ secrets.GITHUB_TOKEN }} fetch-depth: 0 - name: Setup Node @@ -363,7 +356,7 @@ jobs: - name: Version Bump env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | git config user.name "${{ secrets.UI5_WEBCOMP_BOT_NAME }}" git config user.email "${{ secrets.UI5_WEBCOMP_BOT_EMAIL }}"