chore(ci): migrate from PAT to GitHub App token [SEC-58]#4934
chore(ci): migrate from PAT to GitHub App token [SEC-58]#4934maheshkutty merged 17 commits intodevelopfrom
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
Note
|
| Cohort / File(s) | Summary |
|---|---|
Auth & token generation \.github/workflows/validate-actor.yml, \.github/workflows/ingestion-service-test.yml, \.github/workflows/update-ingestion-service.yml, \.github/workflows/prepare-for-prod-dt-deploy.yml, \.github/workflows/prepare-for-prod-rollback.yml, \.github/workflows/prepare-for-prod-ut-deploy.yml, \.github/workflows/prepare-for-staging-deploy.yml, \.github/workflows/draft-new-release.yml, \.github/workflows/publish-new-release.yml, \.github/workflows/create-hotfix-branch.yml, \.github/workflows/build-pr-artifacts.yml |
Removed secrets.PAT inputs/usages; added Generate GitHub App Token steps (actions/create-github-app-token) and replaced PAT references with steps.generate-token.outputs.token for GITHUB_TOKEN/GH_TOKEN, checkout/clone, push, tag, and PR operations. |
Permissions & scoping \.github/workflows/create-hotfix-branch.yml, \.github/workflows/draft-new-release.yml, \.github/workflows/publish-new-release.yml, \.github/workflows/prepare-for-*.yml, \.github/workflows/update-ingestion-service.yml, \.github/workflows/* |
Removed or reduced top-level workflow permissions; introduced per-job permissions blocks (commonly contents: read, id-token: write where needed) to scope access. |
Runner hardening & sequencing \.github/workflows/create-hotfix-branch.yml, \.github/workflows/prepare-for-prod-*.yml, \.github/workflows/update-ingestion-service.yml, \.github/workflows/ingestion-service-test.yml, \.github/workflows/publish-new-release.yml |
Inserted "Harden the runner" steps before network/auth actions and ensured token generation steps run before any git/PR/tag operations. |
API-driven flows & signed commits/tags \.github/workflows/draft-new-release.yml, \.github/workflows/prepare-for-prod-dt-deploy.yml, \.github/workflows/prepare-for-prod-ut-deploy.yml, \.github/workflows/prepare-for-prod-rollback.yml, \.github/workflows/publish-new-release.yml, \.github/workflows/prepare-for-staging-deploy.yml |
Replaced some local git push flows with API-based branch/tag/PR creation and added signed-commit/signed-tag steps; commit/PR creation now often uses GitHub API authenticated by generated token. |
Per-job permission migrations & minor edits \.github/workflows/dt-test-and-report-code-coverage.yml, \.github/workflows/housekeeping.yml, \.github/workflows/build-pr-artifacts.yml, \.github/workflows/check-pr-title.yml, \.github/workflows/commitlint.yml, \.github/workflows/integrations_version_audit.yml, \.github/workflows/prepare-for-dev-deploy.yml, \.github/workflows/slack-notify.yml, \.github/workflows/ut-tests.yml, \.github/workflows/verify-server-start.yml, \.github/workflows/verify.yml, \.github/workflows/build-push-docker-image.yml |
Moved global permissions to per-job permissions; replaced a few isolated secrets.PAT usages with secrets.GITHUB_TOKEN or removed PAT from inputs; no substantial step logic changes besides permission/token wiring. |
Sequence Diagram(s)
sequenceDiagram
autonumber
participant Runner as Actions Runner
participant CreateToken as actions/create-github-app-token
participant GH as GitHub API
participant RepoOps as git/gh/checkout/actions
participant Job as Downstream Job Steps
Runner->>CreateToken: invoke with app-id & private-key
CreateToken->>GH: request installation token (permissions)
GH-->>CreateToken: return installation token
CreateToken-->>Runner: outputs.token (rgba(0,128,255,0.5))
Runner->>RepoOps: perform checkout/clone/commit/push/PR using outputs.token
RepoOps->>GH: authenticated repo/content API calls
GH-->>RepoOps: responses (clone/push/PR results)
Runner->>Job: run downstream steps with GITHUB_TOKEN/GH_TOKEN = outputs.token
Job->>GH: additional authenticated API calls (tags, releases, PRs)
GH-->>Job: responses
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~45 minutes
Suggestions for Improvement
- Consolidate token generation + runner hardening into a reusable composite action to reduce duplicated steps.
- Narrow generated token permissions per-job to least privilege and document required scopes inline.
- Standardize signed-commit/tag helpers (composite action) and retry/backoff for API calls.
- Centralize git user config into a shared step to avoid repeated inline config across workflows.
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | ✅ Passed | The title accurately and concisely summarizes the main objective of the PR—migrating workflow authentication from PAT to GitHub App tokens, with a reference to the security ticket [SEC-58]. |
| Description check | ✅ Passed | The description is comprehensive and well-structured, covering changes summary, architectural improvements, code simplification, rationale, and test plan. All required template sections are addressed with detailed information about the migration scope and benefits. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing Touches
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Post copyable unit tests in a comment
- Commit unit tests in branch
chore/SEC-58-migrate-pat-to-github-app-token
Tip
Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @.github/workflows/validate-actor.yml:
- Around line 24-31: The reusable workflow doesn't expose the
RELEASE_PRIVATE_KEY secret to callers via on.workflow_call, so the
create-github-app-token step (id: generate-token) will receive an empty secret;
update the workflow's on.workflow_call section to declare a secrets block that
includes RELEASE_PRIVATE_KEY (and any other required secrets like RELEASE_APP_ID
if not already declared) so callers can pass it or inherit secrets; ensure the
secret name exactly matches RELEASE_PRIVATE_KEY and remove any mismatch to allow
the generate-token step to access the private key at runtime.
- Around line 11-13: Remove the unnecessary id-token permission from the
workflow permissions block: delete the "id-token: write" entry under
"permissions" while keeping "contents: read" intact; this workflow uses GitHub
App auth via actions/create-github-app-token (app-id/private-key) and does not
require OIDC, so removing "id-token: write" enforces least-privilege.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #4934 +/- ##
===========================================
- Coverage 92.28% 92.27% -0.01%
===========================================
Files 655 657 +2
Lines 35851 35927 +76
Branches 8425 8473 +48
===========================================
+ Hits 33086 33153 +67
+ Misses 2548 2536 -12
- Partials 217 238 +21 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @.github/workflows/ingestion-service-test.yml:
- Around line 34-40: The workflow references secrets.RELEASE_PRIVATE_KEY in the
Generate GitHub App Token step (id: generate-token, uses:
actions/create-github-app-token) but the reusable-workflow input secrets
(on.workflow_call.secrets) only declares DOCKERHUB_TOKEN; add
RELEASE_PRIVATE_KEY to the on.workflow_call.secrets block so callers can pass it
in, and ensure any documentation/README for the reusable workflow notes the
required secret name and purpose.
In @.github/workflows/update-ingestion-service.yml:
- Line 8: The reusable workflow declares workflow_call but never exposes the
secret used later; add a secrets entry under workflow_call to declare
RELEASE_PRIVATE_KEY (e.g. under workflow_call.secrets include
RELEASE_PRIVATE_KEY with required: true or appropriate settings) so steps that
reference secrets.RELEASE_PRIVATE_KEY can access it, or remove the workflow_call
block if the workflow is not intended to be reusable; reference the
workflow_call section and the RELEASE_PRIVATE_KEY secret in your change.
- Around line 43-46: The workflow token scope is limited to
"rudder-ingestion-svc" causing the git push of refs/tags/$GO_TAG (and other
checkout/git operations) to be denied; update the permissions block to include
the current repo (add the current repository name alongside
"rudder-ingestion-svc") and ensure the generated app token is used for checkout
and pushes by wiring it into the actions/checkout and subsequent git commands
(use the token as the checkout "token" input or set GIT_AUTH
environment/credential helper before running git push). Target the permissions
block and the steps that call actions/checkout and the git push
(refs/tags/$GO_TAG) so the generated token has write access to the current repo
and is actually applied to those steps.
🧹 Nitpick comments (1)
.github/workflows/prepare-for-prod-rollback.yml (1)
56-58: Consider: Token in clone URL may appear in logs.The token embedded in the git clone URL is standard practice, but be aware that GitHub Actions masks secrets in logs. Ensure the token output is properly registered as a secret by the
create-github-app-tokenaction (it is by default).As an alternative, you could use git credential helper:
Optional: Use credential helper instead of URL-embedded token
- name: Clone Devops Repo run: | + git config --global url."https://x-access-token:${{ steps.generate-token.outputs.token }}@github.com/".insteadOf "https://github.com/" - git clone https://${{ steps.generate-token.outputs.token }}@github.com/rudderlabs/rudder-devops.git + git clone https://github.com/rudderlabs/rudder-devops.gitThis sets up credentials globally rather than per-URL, which some consider cleaner. However, the current approach works well and is widely used.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @.github/workflows/draft-new-release.yml:
- Around line 30-38: Update the GitHub Action invocation in the "Generate GitHub
App Token" step (id: generate-token) to use the latest stable release of
actions/create-github-app-token by changing the uses reference from
actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42
(v2.1.4) to actions/create-github-app-token@v2.2.1; keep the existing with:
inputs (app-id, private-key, permission-contents, permission-pull-requests)
unchanged and preserve or update the comment to reflect the new version/SHA pin
as needed for supply-chain integrity.
In @.github/workflows/prepare-for-prod-dt-deploy.yml:
- Around line 137-156: The ryancyq/github-signed-commit step fails because it
expects the target branch to already exist remotely; before invoking the action
(the steps using ryancyq/github-signed-commit with branch-name
shared-transformer-${{ env.TAG_NAME }}), create and push the branch using the
generated token: run git checkout -b shared-transformer-${{ env.TAG_NAME }} and
git push -u origin shared-transformer-${{ env.TAG_NAME }} (using GH_TOKEN from
steps.generate-token.outputs.token) so the action can commit; apply the same
change for the other two occurrences where ryancyq/github-signed-commit is used.
In @.github/workflows/prepare-for-staging-deploy.yml:
- Around line 125-130: Update the git clone URL to use the documented GitHub App
token username placeholder by changing the existing git clone invocation that
uses steps.generate-token.outputs.token (the line starting with "git clone
https://${{ steps.generate-token.outputs.token }}@github.com/...") so it uses
"x-access-token" as the username and the token as the password (i.e.,
"https://x-access-token:${{ steps.generate-token.outputs.token
}}@github.com/..."), keeping the rest of the run block (cd rudder-devops, git
config user.name, git config user.email) unchanged.
🧹 Nitpick comments (1)
.github/workflows/draft-new-release.yml (1)
89-98: Consider handling pre-existing branch scenario.If this workflow is re-triggered while a release branch already exists (e.g., from a previous partial run), the API call will fail with a 422 error. While the error is clear, you could make this more robust.
💡 Optional: Check for existing branch before creation
- name: Create Release Branch via GitHub API env: GH_TOKEN: ${{ steps.generate-token.outputs.token }} run: | BASE_SHA=$(git rev-parse origin/main) + BRANCH_NAME="${{ steps.create-release.outputs.branch_name }}" + + # Check if branch already exists + if gh api repos/${{ github.repository }}/git/refs/heads/$BRANCH_NAME --silent 2>/dev/null; then + echo "Branch $BRANCH_NAME already exists, deleting and recreating..." + gh api repos/${{ github.repository }}/git/refs/heads/$BRANCH_NAME --method DELETE + fi + gh api repos/${{ github.repository }}/git/refs \ --method POST \ - -f ref="refs/heads/${{ steps.create-release.outputs.branch_name }}" \ + -f ref="refs/heads/$BRANCH_NAME" \ -f sha="$BASE_SHA"
lvrach
left a comment
There was a problem hiding this comment.
Review: SEC-58 Migration PR
Addressing @maheshkutty's Question
"Is the job level permission is required?" / "I think workflow level permission is sufficient"
Answer: Both approaches work, but there's a key issue with how this PR mixes them:
The Problem: When job-level permissions are specified, they completely override workflow-level permissions (they don't merge). So having both creates confusion:
# Current PR pattern (problematic):
permissions: # workflow level
id-token: write # ← This is ignored when job has permissions
contents: read
jobs:
my-job:
permissions: # job level - OVERRIDES workflow entirely
contents: readRecommendation: Pick ONE approach consistently:
- Option A (Job-level only): Remove all workflow-level
permissions:blocks, keep job-level only - Option B (Workflow-level only): Remove job-level
permissions:blocks, use workflow-level
Either way: Remove id-token: write - it's unused since this PR uses GitHub App auth (not AWS OIDC).
Critical Issues Found (via CodeRabbit + manual review)
1. Missing Secret Declarations in Reusable Workflows
The following reusable workflows use secrets.RELEASE_PRIVATE_KEY but don't declare it in on.workflow_call.secrets:
| File | Issue |
|---|---|
validate-actor.yml |
Missing RELEASE_PRIVATE_KEY declaration |
ingestion-service-test.yml |
Missing RELEASE_PRIVATE_KEY declaration |
update-ingestion-service.yml |
Missing RELEASE_PRIVATE_KEY declaration |
Impact: When invoked as reusable workflows, the secret will be empty and token generation will fail.
Fix: Add to each file:
on:
workflow_call:
secrets:
RELEASE_PRIVATE_KEY:
required: true2. Token Scope Too Narrow in update-ingestion-service.yml
repositories: rudder-ingestion-svc # ← Missing current repo!But the workflow pushes tags to rudder-transformer. The token won't have write access.
Fix: Add current repo:
repositories: rudder-transformer,rudder-ingestion-svc3. Missing Branch Creation Before Signed Commits
ryancyq/github-signed-commit requires the target branch to already exist on remote. In prepare-for-prod-dt-deploy.yml, branches are created locally but not pushed before the action runs.
Affected locations: Lines 137-156, 170-186, 204-220
Fix: Add explicit git push -u origin <branch> before each signed-commit step.
4. Git Clone URL Format
Missing x-access-token: username prefix:
# Current (may fail):
git clone https://${{ token }}@github.com/...
# Correct:
git clone https://x-access-token:${{ token }}@github.com/...Affected files: prepare-for-prod-dt-deploy.yml, prepare-for-prod-rollback.yml, prepare-for-staging-deploy.yml
5. Unused id-token: write Permission
Remove from all workflows - not needed for GitHub App authentication:
validate-actor.ymlprepare-for-prod-dt-deploy.ymlprepare-for-prod-ut-deploy.ymlprepare-for-prod-rollback.ymlprepare-for-staging-deploy.yml
Summary
| Priority | Issue | Files Affected |
|---|---|---|
| 🔴 Critical | Missing secret declarations | 3 reusable workflows |
| 🔴 Critical | Token scope excludes current repo | update-ingestion-service.yml |
| 🟠 Major | Missing branch creation before signed commits | prepare-for-prod-dt-deploy.yml |
| 🟠 Major | Git clone URL format | 3 deploy workflows |
| 🟡 Minor | Unused id-token permission | 5 workflows |
| 🟡 Minor | Mixed permission levels | All modified workflows |
Recommendation: Address the critical issues before merge. The workflows will fail at runtime without these fixes.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @.github/workflows/prepare-for-prod-rollback.yml:
- Around line 42-47: The debug echo in the "Get Target Version" step (id:
target-version) uses an undefined variable $tag_name; replace that reference
with the correctly-assigned local variable $version (or reference the output via
the GITHUB_OUTPUT variable) so the line uses $version when printing the Target
Version.
- Around line 10-13: The reusable workflow call to validate-actor (uses:
./.github/workflows/validate-actor.yml) is missing the required
RELEASE_PRIVATE_KEY secret; update the caller that defines the validate-actor
invocation so it forwards the secret under the secrets block (e.g., add secrets:
RELEASE_PRIVATE_KEY: ${{ secrets.RELEASE_PRIVATE_KEY }} alongside the existing
with: team_names) so the token generation in validate-actor.yml can access
RELEASE_PRIVATE_KEY.
🧹 Nitpick comments (2)
.github/workflows/prepare-for-prod-ut-deploy.yml (1)
116-117: Consider consolidating git config setup.Git user configuration is repeated in three separate steps (lines 116-117, 149-150, 169-170). Since all steps operate in the same
rudder-devopsclone, you could set the config once immediately after cloning.♻️ Optional consolidation
Add a dedicated step after cloning:
- name: Configure Git User run: | cd rudder-devops git config user.name "GitHub Actions" git config user.email "noreply@github.com"Then remove the git config lines from the subsequent steps.
Also applies to: 149-150, 169-170
.github/workflows/prepare-for-staging-deploy.yml (1)
113-116: Remove unnecessary checkout step.The
Checkoutstep at lines 113-116 is not used in thecreate-pull-requestjob. The tag names (TAG_NAME,UT_TAG_NAME) are passed via job outputs, and all file operations occur within the separately-clonedrudder-devopsrepository. Removing this step would reduce workflow execution time and clarify the job's intent.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @.github/workflows/draft-new-release.yml:
- Around line 90-98: The release branch is being created from origin/main
(BASE_SHA) which drops develop/hotfix commits; change the GH API call that
creates the ref for the branch_name (steps.create-release.outputs.branch_name)
to use the current checked-out commit (HEAD) or the computed source_branch_name
instead of origin/main so the new release branch includes the source branch's
commits; locate the block that sets BASE_SHA and the gh api POST (using BASE_SHA
and ref="refs/heads/${{ steps.create-release.outputs.branch_name }}") and
replace BASE_SHA with the SHA of HEAD (or derive the SHA from source_branch_name
output) so the created branch preserves develop/hotfix changes.
In @.github/workflows/prepare-for-prod-dt-deploy.yml:
- Around line 203-205: The checkout currently uses the branch name extracted
from rudder-devops (steps.extract_branch_name.outputs.branch_name) when creating
the new branch in the operator repo (git checkout -b
dedicated-transformer-$TAG_NAME
${{steps.extract_branch_name.outputs.branch_name}}), which will fail if the
operator repo’s default branch differs; change the workflow to determine the
operator repo’s actual default branch after cloning (e.g., run a command to
resolve origin's HEAD or query the repo via GitHub API) and use that resolved
branch name for the git checkout instead of reusing
steps.extract_branch_name.outputs.branch_name, or alternatively ensure both
repos share the same default branch name.
In @.github/workflows/prepare-for-prod-rollback.yml:
- Around line 43-48: The "Get Target Version" step (id: target-version) assigns
version from github.ref_name without quoting (version=${{ github.ref_name }})
which can allow shell metacharacter interpretation; change that and any similar
assignments that interpolate GitHub context or step outputs to use quoted form
(e.g., version="${{ github.ref_name }}") and likewise quote assignments like
branch="${{ steps.<id>.outputs.<name> }}" so interpolated values are treated as
single strings and cannot perform shell injection. Ensure any direct shell
references to these vars later also use quoted expansions (e.g., "$version") to
avoid word-splitting.
🧹 Nitpick comments (7)
.github/workflows/prepare-for-dev-deploy.yml (1)
16-17: Job-level permissions are well-scoped — looks good.Each job declares only the permissions it actually needs:
contents: readfor checkout, andid-token: writeexclusively on jobs that perform AWS OIDC authentication (build and restart jobs). Thegenerate-tag-namesjob correctly omitsid-token: writesince it has no cloud interaction. This aligns well with the least-privilege principle the PR is targeting.One minor suggestion: consider adding a top-level
permissions: {}(empty) as a safety net, so any future job added without explicit permissions defaults to no access rather than the GitHub default (contents: readfor most event types, broader for some). This is a common hardening pattern recommended by StepSecurity and the OpenSSF Scorecard.on: push: branches: - develop +permissions: {} + concurrency:,
Also applies to: 45-47, 63-65, 81-83, 107-109
.github/workflows/create-hotfix-branch.yml (1)
44-49: Consider replacing the third-party branch-creation action with a direct GitHub API call.The PR objectives mention adopting "a simplified pattern that uses the GitHub API for branch creation." Other migrated workflows appear to use this approach. Using
gh apioroctokit/request-actiondirectly would remove the dependency onpeterjgrainger/action-create-branch(which has limited maintenance activity) and keep the approach consistent across workflows.♻️ Example using the GitHub CLI
- name: Create Branch - uses: peterjgrainger/action-create-branch@10c7d268152480ae859347db45dc69086cef1d9c - env: - GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} - with: - branch: 'hotfix/${{ inputs.hotfix_name }}' + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + sha=$(gh api repos/${{ github.repository }}/git/ref/heads/main --jq '.object.sha') + gh api repos/${{ github.repository }}/git/refs \ + --method POST \ + -f ref="refs/heads/hotfix/${{ inputs.hotfix_name }}" \ + -f sha="$sha".github/workflows/prepare-for-staging-deploy.yml (1)
127-162: Consider quoting shell variables to guard against word-splitting.The shell script works correctly for well-formed version strings, but several variables (
$BRANCH_NAME,$TAG_NAME,$UT_TAG_NAME) are used unquoted in contexts where word-splitting or glob expansion could cause unexpected behavior if a value ever contained spaces or special characters. While the current inputs are likely safe (derived frompackage.jsonversion), defensive quoting is a low-cost improvement.For example:
Suggested quoting improvements
BRANCH_NAME="shared-transformer-$TAG_NAME" echo $BRANCH_NAME - if [ -n "$(git ls-remote --heads origin $BRANCH_NAME 2>/dev/null)" ] + if [ -n "$(git ls-remote --heads origin "$BRANCH_NAME" 2>/dev/null)" ] then echo "Staging deployment branch already exists!" else - git checkout -b $BRANCH_NAME + git checkout -b "$BRANCH_NAME" ... - git push -u origin $BRANCH_NAME + git push -u origin "$BRANCH_NAME".github/workflows/prepare-for-prod-rollback.yml (1)
86-93: Redundantgit configfor the same repo — harmless but worth noting.Lines 91–92 re-set
user.name/user.emailinrudder-devops, which was already configured at Lines 59–60 (persisted in.git/config). Not a problem, just slightly redundant. You could extract git config to a shared step or leave it as-is for clarity — up to you..github/workflows/prepare-for-prod-ut-deploy.yml (1)
112-143: Consider using signed commits for consistency with the DT deploy workflow.The
prepare-for-prod-dt-deploy.ymlworkflow usesryancyq/github-signed-commitfor verified commits, whereas this UT workflow still uses traditionalgit commit+git push. If the goal is to produce verified commits across all production deployment workflows, you may want to align this workflow with the DT approach. If this is intentional (e.g., incremental rollout), no action needed — just flagging the discrepancy..github/workflows/prepare-for-prod-dt-deploy.yml (1)
114-157: Thegit addcalls are unnecessary in the signed-commit flow.Since
ryancyq/github-signed-commitreads file contents directly from the working directory and creates the commit via the GitHub GraphQL API, thegit addcalls (lines 124, 128, 132, 136) have no effect on the resulting commit. They're harmless but add noise. The same applies to the hosted transformer (line 176) and dedicated transformer (line 217) flows.You could simplify by removing the
git addcalls and keeping only theyqmodifications, since the signed commit action handles the commit entirely through the API..github/workflows/publish-new-release.yml (1)
72-86:GH_TOKENis set but unused in this step.The
check_tagstep only runsgit fetchandgit rev-parse— neither of which use theGH_TOKENenvironment variable. The checkout step already configured the remote with the App token, so git fetch authenticates via the stored credentials. Consider removingGH_TOKENfrom this step'senvblock to reduce noise and make it clear which steps actually need the token.Proposed cleanup
- name: Check if tag exists id: check_tag env: - GH_TOKEN: ${{ steps.generate-token.outputs.token }} RELEASE_VERSION: ${{ steps.extract-version.outputs.release_version }} run: |
|
This PR is considered to be stale. It has been open for 20 days with no further activity thus it is going to be closed in 7 days. To avoid such a case please consider removing the stale label manually or add a comment to the PR. |
There was a problem hiding this comment.
Pull request overview
Migrates GitHub Actions workflows off a long-lived secrets.PAT to either GITHUB_TOKEN (read/non-triggering ops) or short-lived GitHub App installation tokens (write/cross-repo ops), while standardizing on job-level permission scoping and (in some workflows) API-based verified commits/tags.
Changes:
- Replace PAT usage with GitHub App tokens generated via
actions/create-github-app-token, including updates to reusable workflows and their callers. - Move
permissions:from workflow-level to job-level across workflows to enforce least privilege. - Introduce/expand API-based operations (branch creation / verified commits & tags) in release/deploy automation.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| .github/workflows/verify.yml | Move permissions to job level for PR formatting/lint job. |
| .github/workflows/verify-server-start.yml | Move permissions to job level for server start check. |
| .github/workflows/validate-actor.yml | Replace PAT with GitHub App token for org/team membership validation. |
| .github/workflows/ut-tests.yml | Move permissions to job level for UT test workflow. |
| .github/workflows/update-ingestion-service.yml | Switch cross-repo + PR/tag operations to GitHub App token; job-level permissions. |
| .github/workflows/slack-notify.yml | Move permissions to job level for reusable Slack notifier. |
| .github/workflows/publish-new-release.yml | Use GitHub App token for tag/release/PR operations; add verified tag creation. |
| .github/workflows/prepare-for-staging-deploy.yml | Use GitHub App token for cross-repo helm chart updates; job-level permissions. |
| .github/workflows/prepare-for-prod-ut-deploy.yml | Use GitHub App token for cross-repo helm chart updates; job-level permissions. |
| .github/workflows/prepare-for-prod-rollback.yml | Use GitHub App token + update validate-actor secret wiring; job-level permissions. |
| .github/workflows/prepare-for-prod-dt-deploy.yml | Use GitHub App token + verified commits for cross-repo deploy PRs; job-level permissions. |
| .github/workflows/prepare-for-dev-deploy.yml | Move permissions to job level for OIDC-based deploy steps. |
| .github/workflows/integrations_version_audit.yml | Move permissions to job level for scheduled audit job. |
| .github/workflows/ingestion-service-test.yml | Replace PAT-based cross-repo clone with App-token-authenticated gh repo clone; update required secrets. |
| .github/workflows/housekeeping.yml | Replace PAT with GITHUB_TOKEN for stale/branch cleanup actions; job-level permissions. |
| .github/workflows/dt-test-and-report-code-coverage.yml | Replace PAT with GITHUB_TOKEN for Sonar scan; job-level permissions. |
| .github/workflows/draft-new-release.yml | Replace PAT with GitHub App token; create branch via API; commit via verified API commit action. |
| .github/workflows/create-hotfix-branch.yml | Replace PAT with GitHub App token for branch creation; update validate-actor secret wiring. |
| .github/workflows/commitlint.yml | Move permissions to job level for commitlint workflow. |
| .github/workflows/check-pr-title.yml | Move permissions to job level for PR title validation. |
| .github/workflows/build-push-docker-image.yml | Move permissions to job level for reusable build/push workflow. |
| .github/workflows/build-pr-artifacts.yml | Update reusable workflow calls/permissions; remove PAT secret passing. |
Comments suppressed due to low confidence (1)
.github/workflows/build-pr-artifacts.yml:97
ingestion-service-test.ymlnow requires theRELEASE_PRIVATE_KEYsecret, but this reusable workflow call only passesDOCKERHUB_TOKEN. This will fail workflow validation at runtime with a missing required secret. Pass throughRELEASE_PRIVATE_KEY: ${{ secrets.RELEASE_PRIVATE_KEY }}(or make the callee secret optional if that’s intended).
uses: ./.github/workflows/ingestion-service-test.yml
with:
build_tag: rudderstack/develop-rudder-transformer:${{ needs.generate-tag-names.outputs.tag_name }}
secrets:
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The id-token:write permission is only needed for OIDC authentication (AWS/Azure/GCP). GitHub App token generation uses the App's private key directly and does not require this permission. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace git push patterns with ryancyq/github-signed-commit action to create verified commits via GitHub API. Changes: - draft-new-release.yml: Replace npm run release + git push with signed commit action - prepare-for-prod-dt-deploy.yml: Replace git push with signed commit action for cross-repo operations Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…C-58] - Remove unnecessary git config commands from main repo workflows - Replace git push --set-upstream with GitHub API branch creation in draft-new-release.yml - Move git config to cloned repos where commits actually happen - Follows new simplified pattern with ryancyq/github-signed-commit Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add RELEASE_PRIVATE_KEY to workflow_call.secrets in reusable workflows (validate-actor.yml, ingestion-service-test.yml, update-ingestion-service.yml) - Add branch push steps before ryancyq/github-signed-commit actions (prepare-for-prod-dt-deploy.yml) - Fix token scope to include current repo for tag push (update-ingestion-service.yml) - Add x-access-token: prefix to git clone URLs for proper auth (prepare-for-prod-dt-deploy.yml, prepare-for-prod-rollback.yml, prepare-for-staging-deploy.yml, prepare-for-prod-ut-deploy.yml) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…EC-58] - Move all workflow-level permissions to job-level across 22 files - Fix $tag_name undefined variable in prepare-for-prod-rollback.yml - Declare RELEASE_PRIVATE_KEY in validate-actor.yml workflow_call secrets - Forward RELEASE_PRIVATE_KEY from all 3 callers of validate-actor - Add rudder-transformer to token scope in update-ingestion-service.yml - Wire app token into checkout for tag push in update-ingestion-service.yml - Add x-access-token: prefix to 6 git clone URLs across 4 files - Add id-token:write to jobs needing AWS OIDC (build, ECR, k8s restart) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add inline comments to every job-level permissions entry explaining why the permission is needed and which action/step requires it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
f88a7e6 to
f7db7c1
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
.github/workflows/build-pr-artifacts.yml:97
- The reusable workflow call to
./.github/workflows/ingestion-service-test.ymlno longer passesRELEASE_PRIVATE_KEY, butingestion-service-test.ymldeclares that secret asrequired: trueforworkflow_call. This will cause workflow validation/runtime failure. PassRELEASE_PRIVATE_KEY: ${{ secrets.RELEASE_PRIVATE_KEY }}here (or make the secret optional in the called workflow if intentional).
uses: ./.github/workflows/ingestion-service-test.yml
with:
build_tag: rudderstack/develop-rudder-transformer:${{ needs.generate-tag-names.outputs.tag_name }}
secrets:
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
.github/workflows/build-pr-artifacts.yml:97
- The reusable workflow call to
ingestion-service-test.ymlno longer passes all required secrets.ingestion-service-test.ymlnow requiresRELEASE_PRIVATE_KEY, so this caller will fail validation unless it passes that secret as well (or the called workflow makes it optional).
with:
build_tag: rudderstack/develop-rudder-transformer:${{ needs.generate-tag-names.outputs.tag_name }}
secrets:
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|



Summary
Migrates ALL workflow authentication from
secrets.PATto GitHub App tokens orGITHUB_TOKEN, using the new simplified pattern with GitHub API for branch creation.Linear: SEC-58
Notion: Eliminate Github Bot Users
Changes Summary
Files Migrated to GitHub App Token (9 files)
These workflows create PRs, push branches, or perform cross-repo operations:
permission-members: read(org membership check)contents: write, pull-requests: write+ signed commitscontents: write, pull-requests: writecontents: write(branch creation)contents: write, pull-requests: write+ signed commits, cross-repo:rudder-devops, rudderstack-operatorcontents: write, pull-requests: write, cross-repo:rudder-devopscontents: write, pull-requests: write, cross-repo:rudder-devops, rudderstack-operatorcontents: write, pull-requests: write, cross-repo:rudder-devopscontents: write, pull-requests: write, cross-repo:rudder-ingestion-svccontents: read, cross-repo:rudder-ingestion-svcFiles Migrated to GITHUB_TOKEN (2 files)
These workflows only read data or perform non-triggering operations:
GITHUB_TOKENGITHUB_TOKENFiles Updated (Caller Workflows)
PATsecret fromingestion-service-testcallArchitectural Improvements (January 2026 Guidelines)
✅ Permissions at Job Level
✅ App Token Generated Early
harden-runner✅ Minimal GITHUB_TOKEN Permissions
contents: readat job level✅ Cross-Repo Access via
repositories:✅ Verified Commits via GitHub API
git pushwithryancyq/github-signed-commitactiondraft-new-release.yml: Release version bumps and CHANGELOG updatesprepare-for-prod-dt-deploy.yml: Cross-repo deployment commitsWhy this matters:
Code Simplification (This Update)
✅ Migration Pattern Evolution
This update further simplifies the workflows by removing unnecessary git commands:
Removed (No Longer Needed):
git config user.name/emailin main repo workflows (App identity used instead)git push --set-upstream origin(replaced with GitHub API)Added (API-based approach):
gh api repos/.../git/refsWhy this is better:
ryancyq/github-signed-commit) creates commits via GitHub's GraphQL API, producing verified commits with the App's identityFiles Simplified
draft-new-release.yml: Removed git config, replacedgit push --set-upstreamwith GitHub APIprepare-for-staging-deploy.yml: Removed git config from main flow, moved to cloned repoprepare-for-prod-rollback.yml: Removed git config from main flow, moved to cloned reposprepare-for-prod-ut-deploy.yml: Removed git config from main flow, moved to cloned repoWhy This Migration?
GITHUB_TOKEN, app tokens trigger PR checksTest Plan
🤖 Generated with Claude Code