diff --git a/WORKFLOW.md b/WORKFLOW.md index 2431bb3b..9d2312a0 100644 --- a/WORKFLOW.md +++ b/WORKFLOW.md @@ -196,6 +196,7 @@ The required behaviors, organized by domain. Each is a **MUST**, stated as input - **D8.1 Merge-bot.** Output: enables auto-merge on `opened`/`reopened` for **every** Dependabot tier including semver-major (the required checks are the gate, not the bump magnitude); dispatches `--squash`/`--merge` by the PR's base ref; disables on a maintainer-pushed `synchronize`; concurrency keyed on the **PR number**, not `github.ref`. *Prevents: two PRs colliding in auto-merge.* - **D8.2 CodeGen and Dependabot.** Output: codegen runs as a matrix over both branches and is deterministic from an external source; Dependabot targets both branches, security PRs to default. - **D8.3 Upstream-version tracker.** Output: a scheduled resolver prints a JSON `name -> version` object to a committed state file, opens a rolling per-branch bump PR naming only the moved keys, the merge-bot auto-merges it; the `main` pin push publishes via the release gate, while a `develop` pin does not auto-publish - it ships via a `develop` dispatch (prerelease) or the next promotion to `main`. The tracker's `bump-branch-prefix` + `branches` MUST match the merge-bot's hard-coded `-` head/base pairs, or auto-merge silently never fires. +- **D8.4 An identity allowlist used as a gate fails loud.** Where a gate compares `github.actor` (or a PR author) against hard-coded bot identities, the non-matching branch on an otherwise-legitimate trigger **emits a `::warning::`** rather than falling through silently. Output: a run that declines to act on an unrecognized identity is visibly annotated. *Prevents: the App being renamed, replaced, or reinstalled under a new slug, after which the comparison quietly evaluates false and the gate stops firing - a green, silent run that looks identical to a healthy one.* The masking matters most where a second path hides the loss: a weekly schedule keeps publishing, so the only symptom is release *timeliness*, easily missed for months. Where the failure is self-announcing instead (the merge-bot simply stops merging, so bot PRs visibly pile up) an annotation is optional. Resolving the identity at run time (mint an App token, read `GET /app`) removes the hard-coded string entirely and is the escalation if an allowlist proves fragile in practice. ### D9 - Style / Static (See Section 2) diff --git a/catalog/snippets/workflows/publish-plan-task.yml b/catalog/snippets/workflows/publish-plan-task.yml index 8eaef7f5..b5997d2c 100644 --- a/catalog/snippets/workflows/publish-plan-task.yml +++ b/catalog/snippets/workflows/publish-plan-task.yml @@ -74,6 +74,11 @@ jobs: # ref==main guard keeps the task self-contained even if a caller's push trigger is not main-only. if [[ "$REF" == "main" ]] && { [[ "$ACTOR" == "ptr727-codegen[bot]" ]] || [[ "$ACTOR" == "dependabot[bot]" ]]; }; then publish=true + elif [[ "$REF" == "main" ]]; then + # Fail loud: an unrecognized actor pushing to main is either a human commit (legitimately not + # publishing, but worth seeing) or a release bot under a new identity, which would otherwise + # stop publishing silently while a schedule keeps releasing - lost timeliness, no error. + echo "::warning::Push to main by unrecognized actor '$ACTOR'; not publishing. If this is a release bot under a new identity, update the allowlist in publish-plan-task.yml." fi ;; esac