chore: replace cozystack-bot PAT with cozystack-ci GitHub App

Replace the cozystack-bot personal access token (GH_PAT) with a
GitHub App (cozystack-ci) installation token across all CI/CD
workflows. This improves security by using short-lived, scoped
tokens instead of a long-lived PAT tied to a user account.

Changes:
- tags.yaml: use app token in all 3 jobs (prepare-release,
  generate-changelog, update-website-docs)
- auto-release.yaml: use app token for daily patch releases
- pull-requests-release.yaml: use app token for release finalization

The cozystack-ci GitHub App (ID: 3297617) is installed org-wide
with contents:write and pull-requests:write permissions. Secrets
COZYSTACK_CI_APP_ID and COZYSTACK_CI_PRIVATE_KEY are set at org
level.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
tym83 2026-04-07 01:43:04 +05:00
parent 38624b72de
commit f96b2da199
3 changed files with 81 additions and 41 deletions

View file

@ -20,6 +20,14 @@ jobs:
pull-requests: read
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.COZYSTACK_CI_APP_ID }}
private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }}
owner: cozystack
- name: Checkout code
uses: actions/checkout@v4
with:
@ -28,27 +36,27 @@ jobs:
- name: Configure git
env:
GH_PAT: ${{ secrets.GH_PAT }}
APP_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
git config user.name "cozystack-bot"
git config user.email "217169706+cozystack-bot@users.noreply.github.com"
git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY}
git config user.name "cozystack-ci[bot]"
git config user.email "3297617+cozystack-ci[bot]@users.noreply.github.com"
git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY}
git config --unset-all http.https://github.com/.extraheader || true
- name: Process release branches
uses: actions/github-script@v7
env:
GH_PAT: ${{ secrets.GH_PAT }}
APP_TOKEN: ${{ steps.app-token.outputs.token }}
with:
github-token: ${{ secrets.GH_PAT }}
github-token: ${{ steps.app-token.outputs.token }}
script: |
const { execSync } = require('child_process');
// Configure git to use PAT for authentication
execSync('git config user.name "cozystack-bot"', { encoding: 'utf8' });
execSync('git config user.email "217169706+cozystack-bot@users.noreply.github.com"', { encoding: 'utf8' });
execSync(`git remote set-url origin https://cozystack-bot:${process.env.GH_PAT}@github.com/${process.env.GITHUB_REPOSITORY}`, { encoding: 'utf8' });
// Remove GITHUB_TOKEN extraheader to ensure PAT is used (needed to trigger other workflows)
// Configure git to use GitHub App token for authentication
execSync('git config user.name "cozystack-ci[bot]"', { encoding: 'utf8' });
execSync('git config user.email "3297617+cozystack-ci[bot]@users.noreply.github.com"', { encoding: 'utf8' });
execSync(`git remote set-url origin https://x-access-token:${process.env.APP_TOKEN}@github.com/${process.env.GITHUB_REPOSITORY}`, { encoding: 'utf8' });
// Remove GITHUB_TOKEN extraheader to ensure App token is used (needed to trigger other workflows)
execSync('git config --unset-all http.https://github.com/.extraheader || true', { encoding: 'utf8' });
// Get all release-X.Y branches

View file

@ -23,6 +23,14 @@ jobs:
contains(github.event.pull_request.labels.*.name, 'release')
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.COZYSTACK_CI_APP_ID }}
private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }}
owner: cozystack
# Extract tag from branch name (branch = release-X.Y.Z*)
- name: Extract tag from branch name
id: get_tag
@ -47,11 +55,11 @@ jobs:
- name: Create tag on merge commit
env:
GH_PAT: ${{ secrets.GH_PAT }}
APP_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
git config user.name "cozystack-bot"
git config user.email "217169706+cozystack-bot@users.noreply.github.com"
git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY}
git config user.name "cozystack-ci[bot]"
git config user.email "3297617+cozystack-ci[bot]@users.noreply.github.com"
git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY}
git tag -f ${{ steps.get_tag.outputs.tag }} ${{ github.sha }}
git push -f origin ${{ steps.get_tag.outputs.tag }}
@ -59,7 +67,7 @@ jobs:
- name: Ensure maintenance branch release-X.Y
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GH_PAT }}
github-token: ${{ steps.app-token.outputs.token }}
script: |
const tag = '${{ steps.get_tag.outputs.tag }}'; // e.g. v0.1.3 or v0.1.3-rc3
const match = tag.match(/^v(\d+)\.(\d+)\.\d+(?:[-\w\.]+)?$/);

View file

@ -25,6 +25,14 @@ jobs:
actions: write
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.COZYSTACK_CI_APP_ID }}
private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }}
owner: cozystack
# Check if a non-draft release with this tag already exists
- name: Check if release already exists
id: check_release
@ -115,11 +123,11 @@ jobs:
- name: Commit release artifacts
if: steps.check_release.outputs.skip == 'false'
env:
GH_PAT: ${{ secrets.GH_PAT }}
APP_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
git config user.name "cozystack-bot"
git config user.email "217169706+cozystack-bot@users.noreply.github.com"
git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY}
git config user.name "cozystack-ci[bot]"
git config user.email "3297617+cozystack-ci[bot]@users.noreply.github.com"
git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY}
git config --unset-all http.https://github.com/.extraheader || true
git add .
git commit -m "Prepare release ${GITHUB_REF#refs/tags/}" -s || echo "No changes to commit"
@ -128,13 +136,13 @@ jobs:
- name: Tag API submodule
if: steps.check_release.outputs.skip == 'false'
env:
GH_PAT: ${{ secrets.GH_PAT }}
APP_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
VTAG="${{ steps.tag.outputs.tag }}"
SUBTAG="api/apps/v1alpha1/${VTAG}"
git config user.name "cozystack-bot"
git config user.email "217169706+cozystack-bot@users.noreply.github.com"
git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY}
git config user.name "cozystack-ci[bot]"
git config user.email "3297617+cozystack-ci[bot]@users.noreply.github.com"
git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY}
TARGET="$(git rev-parse "${VTAG}^{}")"
git tag -f "${SUBTAG}" "$TARGET"
git push -f origin "refs/tags/${SUBTAG}"
@ -183,11 +191,11 @@ jobs:
- name: Create release branch
if: steps.check_release.outputs.skip == 'false'
env:
GH_PAT: ${{ secrets.GH_PAT }}
APP_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
git config user.name "cozystack-bot"
git config user.email "217169706+cozystack-bot@users.noreply.github.com"
git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY}
git config user.name "cozystack-ci[bot]"
git config user.email "3297617+cozystack-ci[bot]@users.noreply.github.com"
git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY}
BRANCH="release-${GITHUB_REF#refs/tags/v}"
git branch -f "$BRANCH"
git push -f origin "$BRANCH"
@ -197,7 +205,7 @@ jobs:
if: steps.check_release.outputs.skip == 'false'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GH_PAT }}
github-token: ${{ steps.app-token.outputs.token }}
script: |
const version = context.ref.replace('refs/tags/v', '');
const base = '${{ steps.get_base.outputs.branch }}';
@ -239,6 +247,14 @@ jobs:
pull-requests: write
if: needs.prepare-release.result == 'success'
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.COZYSTACK_CI_APP_ID }}
private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }}
owner: cozystack
- name: Parse tag
id: tag
uses: actions/github-script@v7
@ -261,7 +277,7 @@ jobs:
ref: main
fetch-depth: 0
fetch-tags: true
token: ${{ secrets.GH_PAT }}
token: ${{ steps.app-token.outputs.token }}
- name: Check if changelog already exists
id: check_changelog
@ -289,7 +305,7 @@ jobs:
if: steps.check_changelog.outputs.exists == 'false'
env:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GH_PAT }}
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
copilot --prompt "prepare changelog file for tagged release v${{ steps.tag.outputs.version }}, use @docs/agents/changelog.md for it. Create the changelog file at docs/changelogs/v${{ steps.tag.outputs.version }}.md" \
--allow-all-tools --allow-all-paths < /dev/null
@ -297,11 +313,11 @@ jobs:
- name: Create changelog branch and commit
if: steps.check_changelog.outputs.exists == 'false'
env:
GH_PAT: ${{ secrets.GH_PAT }}
APP_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
git config user.name "cozystack-bot"
git config user.email "217169706+cozystack-bot@users.noreply.github.com"
git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY}
git config user.name "cozystack-ci[bot]"
git config user.email "3297617+cozystack-ci[bot]@users.noreply.github.com"
git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY}
CHANGELOG_FILE="docs/changelogs/v${{ steps.tag.outputs.version }}.md"
CHANGELOG_BRANCH="changelog-v${{ steps.tag.outputs.version }}"
@ -336,7 +352,7 @@ jobs:
if: steps.check_changelog.outputs.exists == 'false'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GH_PAT }}
github-token: ${{ steps.app-token.outputs.token }}
script: |
const version = '${{ steps.tag.outputs.version }}';
const changelogBranch = `changelog-v${version}`;
@ -395,6 +411,14 @@ jobs:
permissions:
contents: read
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.COZYSTACK_CI_APP_ID }}
private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }}
owner: cozystack
- name: Parse tag
id: tag
uses: actions/github-script@v7
@ -414,19 +438,19 @@ jobs:
uses: actions/checkout@v4
with:
repository: cozystack/website
token: ${{ secrets.GH_PAT }}
token: ${{ steps.app-token.outputs.token }}
ref: main
- name: Update docs from release branch
env:
GH_TOKEN: ${{ secrets.GH_PAT }}
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: make update-all BRANCH=release-${{ steps.tag.outputs.version }} RELEASE_TAG=${{ steps.tag.outputs.tag }}
- name: Commit and push
id: commit
run: |
git config user.name "cozystack-bot"
git config user.email "217169706+cozystack-bot@users.noreply.github.com"
git config user.name "cozystack-ci[bot]"
git config user.email "3297617+cozystack-ci[bot]@users.noreply.github.com"
git add content
if git diff --cached --quiet; then
echo "No changes to commit"
@ -443,7 +467,7 @@ jobs:
- name: Open pull request
if: steps.commit.outputs.changed == 'true'
env:
GH_TOKEN: ${{ secrets.GH_PAT }}
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
BRANCH="update-docs-v${{ steps.tag.outputs.version }}"
pr_state=$(gh pr view "$BRANCH" --repo cozystack/website --json state --jq .state 2>/dev/null || echo "")