mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-28 18:19:28 +00:00
ci: migrate AUTOFIX_BOT_PAT to GitHub App token
Replace the long-lived fine-grained PAT (AUTOFIX_BOT_PAT) with short-lived (1-hour) installation access tokens minted via a new get-app-token composite action wrapping actions/create-github-app-token@v3.2.0. The PAT was used in 13 spots across 8 workflow files for gh CLI / GitHub API calls. The per-repo GITHUB_TOKEN (1,000 req/hr) was getting rate-limited when multiple workflows fire concurrently (deploy-site, skills-index, ci-timings, supply-chain-audit, js-autofix). App installation tokens get 5,000 req/hr per installation and are scoped to the App's permissions, not a user account. New composite action: .github/actions/get-app-token/ - Wraps actions/create-github-app-token@bcd2ba49 (v3.2.0, SHA-pinned) - Reads APP_ID + APP_PRIVATE_KEY repo secrets - Outputs a 1hr installation token via steps.app-token.outputs.token Requires two new repo secrets (set after creating the GitHub App): - APP_ID: the App's numeric ID - APP_PRIVATE_KEY: the PEM private key App installation permissions needed: contents: write (js-autofix push, pypi release upload) pull-requests: write (js-autofix PR create/merge, supply-chain comment) issues: write (skills-index-freshness issue creation) actions: write (skills-index workflow trigger) workflows: write (skills-index triggers deploy-site.yml) The AUTOFIX_BOT_PAT secret can be deleted once CI passes on this PR. The comment in js-autofix.yml noting that PAT pushes trigger downstream workflows is updated — App tokens have the same property (they are not GITHUB_TOKEN), so the concurrency-cancel loop logic is unchanged.
This commit is contained in:
parent
b9f82ed39f
commit
7a69b82ad4
9 changed files with 112 additions and 16 deletions
2
.github/actions/detect-changes/action.yml
vendored
2
.github/actions/detect-changes/action.yml
vendored
|
|
@ -7,7 +7,7 @@ description: >-
|
|||
|
||||
inputs:
|
||||
github-token:
|
||||
description: Token for the GitHub API (gh CLI). Pass secrets.AUTOFIX_BOT_PAT from the calling workflow.
|
||||
description: Token for the GitHub API (gh CLI). Pass steps.app-token.outputs.token from the calling workflow.
|
||||
required: false
|
||||
default: ${{ github.token }}
|
||||
|
||||
|
|
|
|||
59
.github/actions/get-app-token/action.yml
vendored
Normal file
59
.github/actions/get-app-token/action.yml
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
name: Get GitHub App Token
|
||||
description: >-
|
||||
Mint a short-lived (1-hour) installation access token from the repo's
|
||||
GitHub App, replacing the long-lived AUTOFIX_BOT_PAT. App tokens get
|
||||
5,000 req/hr per installation (vs 1,000 for the default GITHUB_TOKEN)
|
||||
and are scoped to the App's installation permissions, not a user account.
|
||||
|
||||
Falls back to the built-in GITHUB_TOKEN when APP_ID is not set — this
|
||||
happens on fork PRs where repo secrets are unavailable. The fallback
|
||||
ensures classification, timings, and review comments still work on
|
||||
forks (with the lower GITHUB_TOKEN rate limit).
|
||||
|
||||
Requires two repo secrets (store when creating the App):
|
||||
- APP_ID — the App's numeric ID (Settings → General)
|
||||
- APP_PRIVATE_KEY — the PEM private key (Settings → Private keys)
|
||||
|
||||
The App must be installed on the repository (or org) with the
|
||||
permissions the calling workflow needs.
|
||||
|
||||
inputs:
|
||||
owner:
|
||||
description: Repository owner (for cross-org tokens). Defaults to the current repo's owner.
|
||||
required: false
|
||||
default: ${{ github.repository_owner }}
|
||||
|
||||
outputs:
|
||||
token:
|
||||
description: A GitHub App installation access token (1-hour TTL), or GITHUB_TOKEN on forks.
|
||||
value: ${{ steps.app-token.outputs.token || steps.fallback.outputs.token }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Check if App credentials exist
|
||||
id: check
|
||||
shell: bash
|
||||
env:
|
||||
APP_ID: ${{ secrets.APP_ID }}
|
||||
run: |
|
||||
if [ -n "$APP_ID" ]; then
|
||||
echo "has_app=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "has_app=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Create GitHub App token
|
||||
id: app-token
|
||||
if: steps.check.outputs.has_app == 'true'
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
with:
|
||||
app-id: ${{ secrets.APP_ID }}
|
||||
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
||||
owner: ${{ inputs.owner }}
|
||||
|
||||
- name: Fall back to GITHUB_TOKEN
|
||||
id: fallback
|
||||
if: steps.check.outputs.has_app != 'true'
|
||||
shell: bash
|
||||
run: echo "token=${{ github.token }}" >> "$GITHUB_OUTPUT"
|
||||
17
.github/workflows/ci.yml
vendored
17
.github/workflows/ci.yml
vendored
|
|
@ -49,13 +49,16 @@ jobs:
|
|||
event_name: ${{ github.event_name }}
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Get GitHub App token
|
||||
id: app-token
|
||||
uses: ./.github/actions/get-app-token
|
||||
- name: Detect affected areas
|
||||
id: classify
|
||||
uses: ./.github/actions/detect-changes
|
||||
with:
|
||||
# Forks get no repo secrets (AUTOFIX_BOT_PAT is empty); fall back to
|
||||
# the built-in read-only token so classification still works there.
|
||||
github-token: ${{ secrets.AUTOFIX_BOT_PAT || github.token }}
|
||||
# The get-app-token composite action falls back to GITHUB_TOKEN
|
||||
# on fork PRs where APP_ID is unavailable.
|
||||
github-token: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────
|
||||
# Lane-gated sub-workflows. Each runs in parallel after detect finishes.
|
||||
|
|
@ -318,6 +321,10 @@ jobs:
|
|||
- name: Checkout code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Get GitHub App token
|
||||
id: app-token
|
||||
uses: ./.github/actions/get-app-token
|
||||
|
||||
- name: Restore baseline cache (PR only)
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
|
|
@ -334,7 +341,9 @@ jobs:
|
|||
# Forks get no repo secrets (AUTOFIX_BOT_PAT is empty); fall back to
|
||||
# the built-in read-only token so the timings API read still works
|
||||
# there instead of hard-failing this advisory job on every fork PR.
|
||||
GITHUB_TOKEN: ${{ secrets.AUTOFIX_BOT_PAT || github.token }}
|
||||
# The get-app-token composite action falls back to GITHUB_TOKEN
|
||||
# on fork PRs where APP_ID is unavailable.
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
run: |
|
||||
python3 scripts/ci/timings_report.py \
|
||||
--baseline ci-timings-baseline.json \
|
||||
|
|
|
|||
8
.github/workflows/deploy-site.yml
vendored
8
.github/workflows/deploy-site.yml
vendored
|
|
@ -56,6 +56,10 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Get GitHub App token
|
||||
id: app-token
|
||||
uses: ./.github/actions/get-app-token
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
|
@ -73,8 +77,8 @@ jobs:
|
|||
|
||||
- name: Prepare skills index (unified multi-source catalog)
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.AUTOFIX_BOT_PAT }}
|
||||
GITHUB_TOKEN: ${{ secrets.AUTOFIX_BOT_PAT }}
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
SKILLS_INDEX_RUN_ID: ${{ github.event.inputs.skills_index_run_id || '' }}
|
||||
REBUILD_SKILLS_INDEX: ${{ github.event.inputs.rebuild_skills_index || 'false' }}
|
||||
run: |
|
||||
|
|
|
|||
10
.github/workflows/js-autofix.yml
vendored
10
.github/workflows/js-autofix.yml
vendored
|
|
@ -7,7 +7,7 @@ name: auto-fix lint issues & formatting
|
|||
# auto-corrected on merge so PRs aren't blocked by them. The PR-time eslint
|
||||
# check in typecheck.yml fails only when un-fixable errors remain.
|
||||
#
|
||||
# NOTE: AUTOFIX_BOT_PAT pushes DO trigger further workflow runs (unlike
|
||||
# NOTE: App token pushes DO trigger further workflow runs (unlike
|
||||
# secrets.GITHUB_TOKEN). The concurrency group (ts-autofix-${{ github.ref }})
|
||||
# with cancel-in-progress: true prevents an infinite loop — a re-triggered
|
||||
# run cancels the in-flight one, and since the second run finds no new fixes
|
||||
|
|
@ -128,6 +128,10 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Get GitHub App token
|
||||
id: app-token
|
||||
uses: ./.github/actions/get-app-token
|
||||
|
||||
- name: Download patch
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||
with:
|
||||
|
|
@ -170,7 +174,7 @@ jobs:
|
|||
|
||||
- name: Create/update PR and enable auto-merge
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.AUTOFIX_BOT_PAT }}
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
BOT_BRANCH: bot/js-autofix
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
|
@ -193,7 +197,7 @@ jobs:
|
|||
|
||||
- name: Wait for merge, auto-close on failure or stale
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.AUTOFIX_BOT_PAT }}
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
START_SHA: ${{ github.sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
|
|
|||
7
.github/workflows/skills-index-freshness.yml
vendored
7
.github/workflows/skills-index-freshness.yml
vendored
|
|
@ -108,10 +108,15 @@ jobs:
|
|||
echo "Summary: ${{ steps.probe.outputs.summary }}"
|
||||
fi
|
||||
|
||||
- name: Get GitHub App token
|
||||
if: steps.probe.outputs.status != 'ok'
|
||||
id: app-token
|
||||
uses: ./.github/actions/get-app-token
|
||||
|
||||
- name: Open issue on degraded / failed probe
|
||||
if: steps.probe.outputs.status != 'ok'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.AUTOFIX_BOT_PAT }}
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
STATUS: ${{ steps.probe.outputs.status }}
|
||||
DETAIL: ${{ steps.probe.outputs.detail }}
|
||||
run: |
|
||||
|
|
|
|||
11
.github/workflows/skills-index.yml
vendored
11
.github/workflows/skills-index.yml
vendored
|
|
@ -24,6 +24,10 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Get GitHub App token
|
||||
id: app-token
|
||||
uses: ./.github/actions/get-app-token
|
||||
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
|
@ -35,7 +39,7 @@ jobs:
|
|||
|
||||
- name: Build skills index
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.AUTOFIX_BOT_PAT }}
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
run: python scripts/build_skills_index.py
|
||||
|
||||
- name: Upload index artifact
|
||||
|
|
@ -54,7 +58,10 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Get GitHub App token
|
||||
id: app-token
|
||||
uses: ./.github/actions/get-app-token
|
||||
- name: Trigger Deploy Site workflow
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.AUTOFIX_BOT_PAT }}
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
run: gh workflow run deploy-site.yml --repo ${{ github.repository }} -f skills_index_run_id=${{ github.run_id }}
|
||||
|
|
|
|||
6
.github/workflows/supply-chain-audit.yml
vendored
6
.github/workflows/supply-chain-audit.yml
vendored
|
|
@ -60,10 +60,14 @@ jobs:
|
|||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get GitHub App token
|
||||
id: app-token
|
||||
uses: ./.github/actions/get-app-token
|
||||
|
||||
- name: Scan diff for critical patterns
|
||||
id: scan
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.AUTOFIX_BOT_PAT }}
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
|
|
|
|||
8
.github/workflows/upload_to_pypi.yml
vendored
8
.github/workflows/upload_to_pypi.yml
vendored
|
|
@ -143,9 +143,13 @@ jobs:
|
|||
name: python-package-distributions
|
||||
path: dist/
|
||||
|
||||
- name: Get GitHub App token
|
||||
id: app-token
|
||||
uses: ./.github/actions/get-app-token
|
||||
|
||||
- name: Wait for GitHub Release to exist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.AUTOFIX_BOT_PAT }}
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
# release.py creates the GitHub Release after pushing the tag,
|
||||
# but this workflow starts from the tag push — wait for it.
|
||||
run: |
|
||||
|
|
@ -171,7 +175,7 @@ jobs:
|
|||
- name: Attach signed artifacts to GitHub Release
|
||||
if: env.skip_sign != 'true'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.AUTOFIX_BOT_PAT }}
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
# release.py already created the GitHub Release — just upload
|
||||
# the Sigstore signatures alongside the existing assets.
|
||||
run: >-
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue