Replace cozystack-bot PAT with cozystack-ci GitHub App (#2351)
## Summary Replaces the `cozystack-bot` user account + personal access token (`GH_PAT`) with the `cozystack-ci` GitHub App across all CI/CD release workflows. ### Why - **Security**: GitHub App tokens are short-lived (1h) and scoped, vs. a long-lived PAT tied to a user account - **Auditability**: App actions are clearly attributed to `cozystack-ci[bot]` - **No 2FA issue**: The bot account lacked 2FA; GitHub Apps don't require it - **Best practice**: GitHub recommends Apps over PATs for automation ### Changes | Workflow | What changed | |---|---| | `tags.yaml` | App token in all 3 jobs: prepare-release, generate-changelog, update-website-docs | | `auto-release.yaml` | App token for daily auto-patch tagging | | `pull-requests-release.yaml` | App token for release PR finalization | All `cozystack-bot` git identity replaced with `cozystack-ci[bot]`. ### New secrets (already configured at org level) - `COZYSTACK_CI_APP_ID` — GitHub App ID - `COZYSTACK_CI_PRIVATE_KEY` — GitHub App private key ### After merge - [ ] Delete `GH_PAT` repo-level secret - [ ] Remove `cozystack-bot` from the cozystack org 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Updated CI/CD automation authentication mechanisms across release and tagging workflows for improved security practices. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
This commit is contained in:
parent
94f5b79390
commit
8b1f29975c
3 changed files with 81 additions and 41 deletions
30
.github/workflows/auto-release.yaml
vendored
30
.github/workflows/auto-release.yaml
vendored
|
|
@ -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
|
||||
|
|
|
|||
18
.github/workflows/pull-requests-release.yaml
vendored
18
.github/workflows/pull-requests-release.yaml
vendored
|
|
@ -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\.]+)?$/);
|
||||
|
|
|
|||
74
.github/workflows/tags.yaml
vendored
74
.github/workflows/tags.yaml
vendored
|
|
@ -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 "")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue