Skip to content
16 changes: 11 additions & 5 deletions .github/workflows/dependabot-rebase-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,19 @@ jobs:
if GH_TOKEN="$APP_TOKEN" gh api "repos/$REPO/pulls/$PR_NUMBER/update-branch" \
-X PUT 2>/dev/null; then
echo " Updated branch for PR #$PR_NUMBER"
else
echo " Warning: could not update branch for PR #$PR_NUMBER (may have conflicts)"
continue # wait for CI on updated branch before merging
fi
continue
fi

echo "PR #$PR_NUMBER ($HEAD_REF) is up to date — checking if merge-ready"
# update-branch failed (e.g. App lacks 'workflows' permission when
# main contains workflow file changes, or there is a merge conflict).
# Fall through to the merge attempt — the bypass actor (bypass_mode:always)
# can merge directly even when the branch is behind, provided the PR's
# own CI has already passed and the strict_required_status_checks_policy
# is false (which it is for this org).
echo " Warning: could not update branch for PR #$PR_NUMBER — will attempt direct merge"
else
echo "PR #$PR_NUMBER ($HEAD_REF) is up to date — checking if merge-ready"
fi

# Skip if we already merged one (strict mode means others are now behind)
if [[ "$MERGED" == "true" ]]; then
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/dependabot-rebase.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ on:
push:
branches:
- main
schedule:
- cron: '0 */4 * * *' # every 4 hours — safety net when no pushes to main trigger the chain
workflow_dispatch: # allow manual trigger to flush Dependabot PR queue
Comment on lines 31 to 37

concurrency:
Expand Down
32 changes: 29 additions & 3 deletions standards/dependabot-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,25 @@ This workflow fires on every push to `main` (and can be triggered manually via
Using the app token for merges ensures each merge triggers a new push to `main`,
creating a self-sustaining chain that serializes Dependabot PR merges.

**GitHub App permission requirement:** The `dependabot-automerge-petry` GitHub App
must have the `workflows` permission granted. Without it, the `update-branch` API
call fails with *"refusing to allow a GitHub App to create or update workflow"*
whenever `main` contains workflow file changes (`.github/workflows/*.yml`) that
would be merged into the PR branch. Grant the permission in the GitHub App settings:
Settings → GitHub Apps → dependabot-automerge-petry → Permissions → Workflows → Read & Write.

**Chain-stall safety net:** The rebase workflow also runs on a 4-hour schedule
(`cron: '0 */4 * * *'`) in addition to `push: main` and `workflow_dispatch`.
This prevents the serialization chain from stalling in repos where no PR merges
to `main` occur for extended periods, without relying solely on external pushes.

**Fallback merge when `update-branch` fails:** If `update-branch` fails (e.g., the
GitHub App lacks the `workflows` permission or there are merge conflicts), the
workflow falls through to the direct merge attempt instead of skipping the PR
permanently. The bypass actor (`bypass_mode: always`) can call `gh api .../merge`
directly even when the branch is behind `main`, as long as the PR's own CI has
passed and `strict_required_status_checks_policy` is `false`.

**Why `update-branch` with APP_TOKEN (not `GITHUB_TOKEN` or `@dependabot rebase`):**

- **`GITHUB_TOKEN`** is subject to GitHub's recursive-trigger guard — events it
Expand Down Expand Up @@ -297,7 +316,14 @@ The workflow fails if any known vulnerability is found, blocking the PR from mer
> [CODEOWNERS Standard](codeowners-standard.md). The earlier approach of
> using `gh api .../merge` as a bypass was fragile and has been superseded.
4. Add `workflows/dependency-audit.yml` to `.github/workflows/`.
5. **GitHub App secrets** — `APP_ID` and `APP_PRIVATE_KEY` are managed at the
5. **GitHub App permissions** — the `dependabot-automerge-petry` GitHub App requires
the `workflows` permission in addition to `contents: write` and `pull_requests: write`.
Without it, the rebase workflow cannot call `update-branch` when `main` contains
workflow file changes. Grant: GitHub App settings → Permissions → Repository →
Workflows → Read & Write, then accept the updated permission in each repo's
installed-app settings.

6. **GitHub App secrets** — `APP_ID` and `APP_PRIVATE_KEY` are managed at the
**organization level** (`gh secret set <name> --org petry-projects --visibility all`),
not per-repo. The caller stubs pass these explicitly via:

Expand All @@ -321,9 +347,9 @@ The workflow fails if any known vulnerability is found, blocking the PR from mer
both secrets are confirmed should you run `gh secret delete APP_ID --repo <repo>`
to clean up per-repo copies — otherwise `gh pr review` calls fail with
`Secret APP_ID is required`.
6. Create the `security` and `dependencies` labels in the repository if they
7. Create the `security` and `dependencies` labels in the repository if they
don't already exist.
7. Add `dependency-audit / Detect ecosystems` as a required status check in
8. Add `dependency-audit / Detect ecosystems` as a required status check in
branch protection rules. Do **not** require the per-ecosystem audit jobs
(`npm audit`, `govulncheck`, `cargo audit`, `pip-audit`, `pnpm audit`) —
they're conditional on lockfile presence and report `SKIPPED` when absent,
Expand Down
7 changes: 5 additions & 2 deletions standards/workflows/dependabot-rebase.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
# • You MUST NOT change: the concurrency group name, the explicit secrets
# block, or the job-level `permissions:` block — reusable workflows can be
# granted no more permissions than the calling job has, so removing the
# stanza breaks the reusable's gh API calls. Do not remove either trigger
# (`push` keeps the self-sustaining chain; `workflow_dispatch` allows
# stanza breaks the reusable's gh API calls. Do not remove any trigger
# (`push` keeps the self-sustaining chain; `schedule` is the safety net
# when no PR merges have occurred recently; `workflow_dispatch` allows
# manual queue flushes).
# • If you need different behaviour, open a PR against the reusable in the
# central repo.
Expand All @@ -29,6 +30,8 @@ on:
push:
branches:
- main
schedule:
- cron: '0 */4 * * *' # every 4 hours — safety net when no pushes to main trigger the chain
workflow_dispatch: # allow manual trigger to flush Dependabot PR queue

concurrency:
Expand Down
Loading