ci: Add additional alerts for CI failures (#37398)

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
This commit is contained in:
Matsu
2026-09-01 10:40:58 +03:00
committed by GitHub
co-authored by cubic-dev-ai[bot]
parent 691bf7bdfc
commit a0585d84ba
3 changed files with 80 additions and 5 deletions
+11 -5
View File
@@ -805,14 +805,20 @@ Embargoed security work happens in `n8n-io/n8n-private`. `sec-sync-public-to-pri
runs hourly there (and on `workflow_dispatch` with `force` for conflict recovery),
mirroring public `master` and `1.x` into private with `reset --hard` +
`--force-with-lease` — skipping a branch when private is ahead, ignoring `chore: Bundle`
commits when judging "ahead". Fixes are never committed to private `master`/`1.x`
directly: `ci-restrict-private-merges.yml` requires PRs into them to come from the
long-lived integration branches `bundle/2.x` and `bundle/1.x` (a `bundle/2.x` merge is
commits when judging "ahead". A skipped branch, or a hard failure, is reported to
`#alerts-build`: a non-`chore: Bundle` commit on private `master`/`1.x` leaves the mirror
stuck every hour until it is removed or a `force` dispatch overwrites it. Fixes are never
committed to private `master`/`1.x` directly: `ci-restrict-private-merges.yml` requires
PRs into them to come from the long-lived integration
branches `bundle/2.x` and `bundle/1.x` (a `bundle/2.x` merge is
backported to `bundle/1.x` by `util-backport-bundle.yml`). Once a bundle branch is merged
into private `master`/`1.x` as a `chore: Bundle/*` PR, `sec-publish-fix.yml` /
`sec-publish-fix-1x.yml` cherry-pick that commit onto a fresh branch in the public repo and
open the PR there. That PR **must stay a single-parent squash** — the publish step is a bare
`git cherry-pick` of `HEAD`, which aborts on a merge commit.
`git cherry-pick` of `HEAD`, which aborts on a merge commit. A `chore: Bundle/*` PR whose
*Required Checks* go red holds back every fix batched into it, so `ci-pull-requests.yml`
posts to `#alerts-build` when that gate fails on a PR opened *from* `bundle/2.x` or
`bundle/1.x` (link only, no PR title, since the branch is embargoed).
`sec-sync-bundle-branches.yml` keeps those branches current, daily plus whenever a PR is
merged into one (and on `workflow_dispatch`). It **merges the base into** the bundle branch
@@ -886,7 +892,7 @@ If notify is a step inside an existing checked-out job, skip the `checkout` and
| `QBOT_SLACK_TOKEN` | QBot | Default — engineering / build / security |
| `RELEASE_HELPER_SLACK_TOKEN` | Release Helper | `#releases` (C036AELNMV0) |
Adding a new channel requires inviting the bot first; the first run otherwise fails loudly with `not_in_channel`. Private-repo workflows (`sec-publish-fix*.yml`) need `QBOT_SLACK_TOKEN` set in `n8n-io/n8n-private`; the scripts themselves are mirrored by `sec-sync-public-to-private.yml`.
Adding a new channel requires inviting the bot first; the first run otherwise fails loudly with `not_in_channel`. Private-repo workflows (`sec-publish-fix*.yml`, `sec-sync-public-to-private.yml`, and the bundle-PR alert in `ci-pull-requests.yml`) need `QBOT_SLACK_TOKEN` set in `n8n-io/n8n-private`; the scripts themselves are mirrored by `sec-sync-public-to-private.yml`.
---
+27
View File
@@ -412,6 +412,33 @@ jobs:
mode: validate
job-results: ${{ toJSON(needs) }}
# A red `chore: Bundle/*` PR blocks publishing every fix batched into it, so the
# failure is announced instead of waiting to be noticed. Only fires in n8n-private,
# where bundle branches exist.
notify-bundle-pr-failure:
name: Notify Slack on bundle PR failure
needs: required-checks
if: >-
always() &&
needs.required-checks.result == 'failure' &&
(github.head_ref == 'bundle/2.x' || github.head_ref == 'bundle/1.x')
runs-on: ubuntu-slim
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout: .github/scripts/slack
sparse-checkout-cone-mode: false
- name: Notify Slack
env:
SLACK_TOKEN: ${{ secrets.QBOT_SLACK_TOKEN }}
HEAD_REF: ${{ github.head_ref }}
PR_URL: ${{ github.event.pull_request.html_url }}
run: |
node .github/scripts/slack/notify.mjs \
--channel '#alerts-build' \
--text "<${PR_URL}|Required Checks failed on the ${HEAD_REF} PR> - the batched fixes stay unpublished until it is green."
# Posts a QA metrics comparison comment on the PR.
# Runs after all checks so any job can emit metrics before this reports.
post-qa-metrics-comment:
@@ -6,6 +6,8 @@
# Scheduled runs only sync if private is not ahead of public.
# Manual runs always sync (for conflict recovery after failed cherry-pick).
#
# A skipped branch or a hard failure is reported to #alerts-build.
#
# The bundle/* integration branches are kept current by sec-sync-bundle-branches.yml.
name: 'Security: Sync from Public'
@@ -44,6 +46,7 @@ jobs:
token: ${{ steps.app-token.outputs.token }}
- name: Sync master from public
id: sync-master
env:
EVENT_NAME: ${{ github.event_name }}
FORCE: ${{ inputs.force }}
@@ -56,9 +59,11 @@ jobs:
if [ "$AHEAD_COUNT" -gt 0 ]; then
if [ "$EVENT_NAME" = "schedule" ]; then
echo "Private is $AHEAD_COUNT commit(s) ahead of public, skipping scheduled sync"
echo "ahead_count=$AHEAD_COUNT" >> "$GITHUB_OUTPUT"
exit 0
elif [ "$FORCE" != "true" ]; then
echo "Private is $AHEAD_COUNT commit(s) ahead of public, skipping (force not enabled)"
echo "ahead_count=$AHEAD_COUNT" >> "$GITHUB_OUTPUT"
exit 0
else
echo "Private is $AHEAD_COUNT commit(s) ahead of public, force syncing anyway"
@@ -69,6 +74,7 @@ jobs:
git push origin master --force-with-lease
- name: Sync 1.x from public
id: sync-1x
env:
EVENT_NAME: ${{ github.event_name }}
FORCE: ${{ inputs.force }}
@@ -82,9 +88,11 @@ jobs:
if [ "$AHEAD_COUNT" -gt 0 ]; then
if [ "$EVENT_NAME" = "schedule" ]; then
echo "Private 1.x is $AHEAD_COUNT commit(s) ahead of public, skipping scheduled sync"
echo "ahead_count=$AHEAD_COUNT" >> "$GITHUB_OUTPUT"
exit 0
elif [ "$FORCE" != "true" ]; then
echo "Private 1.x is $AHEAD_COUNT commit(s) ahead of public, skipping (force not enabled)"
echo "ahead_count=$AHEAD_COUNT" >> "$GITHUB_OUTPUT"
exit 0
else
echo "Private 1.x is $AHEAD_COUNT commit(s) ahead of public, force syncing anyway"
@@ -114,3 +122,37 @@ jobs:
echo "Missing: ${MISSING[*]} - dispatching Security: Sync Bundle Branches"
gh workflow run sec-sync-bundle-branches.yml --ref master
- name: Notify Slack on failure
if: failure()
env:
SLACK_TOKEN: ${{ secrets.QBOT_SLACK_TOKEN }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
continue-on-error: true
run: |
node .github/scripts/slack/notify.mjs \
--channel '#alerts-build' \
--text "<${RUN_URL}|Public → private sync failed>"
- name: Notify Slack on skipped sync
continue-on-error: true
if: ${{ !cancelled() && (steps.sync-master.outputs.ahead_count || steps.sync-1x.outputs.ahead_count) }}
env:
SLACK_TOKEN: ${{ secrets.QBOT_SLACK_TOKEN }}
MASTER_AHEAD: ${{ steps.sync-master.outputs.ahead_count }}
ONE_X_AHEAD: ${{ steps.sync-1x.outputs.ahead_count }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
DETAILS=''
if [ -n "$MASTER_AHEAD" ]; then
DETAILS="master is $MASTER_AHEAD commit(s) ahead"
fi
if [ -n "$ONE_X_AHEAD" ]; then
[ -z "$DETAILS" ] || DETAILS="$DETAILS, "
DETAILS="${DETAILS}1.x is $ONE_X_AHEAD commit(s) ahead"
fi
# Non-Bundle commits on private master/1.x keep the sync skipped until they are removed or force-synced
node .github/scripts/slack/notify.mjs \
--channel '#alerts-build' \
--text "<${RUN_URL}|Public → private sync skipped>: ${DETAILS} of public. Re-run with force once resolved."