Chaining GitHub Actions Workflows Without a PAT or GitHub App
How to trigger one workflow from another when you can’t (or don’t want to) use Personal Access Tokens or GitHub Apps.
The Problem
You have two workflows:
- Workflow A — Detects branches and auto-creates PRs against main
- Workflow B — Runs tests on PRs opened against main
Manual PRs trigger Workflow B. But when Workflow A creates a PR, Workflow B never runs.
Why This Happens
GitHub Actions has a deliberate security feature:
Actions performed using the default
GITHUB_TOKENdo not trigger other workflows.
This prevents accidental infinite loops (Workflow A triggers B triggers A triggers B…). When Workflow A creates a PR using GITHUB_TOKEN, GitHub suppresses the pull_request event that Workflow B listens for.
Mitigation Options
| Option | How It Works | Pros | Cons |
|---|---|---|---|
| Personal Access Token | Use a PAT instead of GITHUB_TOKEN | Simple | Tied to user account, expires, requires secret management |
| GitHub App | Create app, use its token | Not tied to user, fine-grained permissions | Requires app creation/management, may need org admin access |
workflow_run trigger | Workflow B triggers on Workflow A completion | No extra tokens, works within default permissions | Slightly more complex logic |
Why Not PAT or GitHub App?
In enterprise environments, engineers often:
- Don’t have permission to create GitHub Apps at the org level
- Can’t or shouldn’t create PATs tied to personal accounts for shared workflows
- Face security policies that restrict token creation
- Need solutions that work within the default
GITHUB_TOKENpermissions
The workflow_run approach works entirely within GitHub’s default permission model.
Solution: Using workflow_run Trigger
Instead of Workflow B listening for pull_request events (which won’t fire), have it listen for Workflow A’s completion.
Architecture
┌─────────────────┐ ┌─────────────────┐
│ Workflow A │ │ Workflow B │
│ (Auto-Create PR)│ │ (Run Tests) │
└────────┬────────┘ └────────▲────────┘
│ │
│ completes │ triggers on
│ │ workflow_run
▼ │
┌────────────┐ │
│ PR │───────────────────┘
│ Created │ (B finds PR from A's run)
└────────────┘Implementation
Workflow A: Auto-Create PR
Workflow B: Run Tests on Workflow A Completion
Key Points
Dual triggers: Workflow B responds to both
pull_request(manual PRs) andworkflow_run(auto PRs)Conditional logic: The
ifcondition ensures we only run on successful Workflow A completionsPR discovery: Since
workflow_rundoesn’t have PR context, we query the API to find the PR by branch nameStatus reporting: We manually create commit statuses so the PR shows test results
Caveats
Check Runs and PR Status
When triggered via workflow_run, the workflow runs in the context of the default branch, not the PR. This means:
- PR checks list won’t automatically show the workflow
- You need to manually create commit statuses (shown above)
- Or use the Checks API to create check runs
Race Conditions
If Workflow A completes before the PR is fully created (rare but possible), the PR lookup might fail. Add a short delay or retry logic if needed:
Branch Name Matching
The PR lookup uses the head branch. Ensure Workflow A’s branch naming is predictable so Workflow B can find the right PR.
Verification
After implementing:
- Push a branch matching your pattern (e.g.,
feature/test-chain) - Confirm Workflow A runs and creates the PR
- Confirm Workflow B triggers on Workflow A completion
- Confirm tests run and status appears on the PR
Summary
The workflow_run trigger lets you chain workflows without PATs or GitHub Apps. It’s slightly more complex than the token-based approaches, but works entirely within GitHub’s default permission model — making it ideal for enterprise environments where token creation is restricted.