Skip to content

STAC-25533: report release-branch CI failures to Slack via Cerberus - #366

Merged
LouisParkin merged 8 commits into
stackstate-7.78.2from
STAC-25533-cerberus-notify
Aug 7, 2026
Merged

STAC-25533: report release-branch CI failures to Slack via Cerberus#366
LouisParkin merged 8 commits into
stackstate-7.78.2from
STAC-25533-cerberus-notify

Conversation

@LouisParkin

Copy link
Copy Markdown
Contributor

This pipeline has never had a failure notification — the retired .gitlab-ci.yml had no notify job and no .cerberus directory, so a broken release branch is silent. STAC-25510 is what that costs: process-agent's image publishing broke and nobody noticed for 12 days.

Adds a reusable cerberus-notify.yml (structurally identical to the one process-agent gained in STAC-25519) and calls it as a terminal job off ci-success.

Worth a look:

  • Push events only. Given the existing push: trigger that means the release branch and release tags. PR failures already have an owner watching, and on a public repo anyone can open a deliberately-failing PR — notifying on those hands the CI channel a spam vector. Keyed on github.event_name rather than a hardcoded ref so the next release-branch bump touches one place, not two.
  • action: notify, never block. Blocking locks the branch, needs the Cerberus App installed here, and mutates the branch protection pulumi-infra now owns (STAC-25522).

Depends on StackVista/pulumi-infra#277 for the repo-level secrets (the org copies are visibility=private; this repo is public). Until that merges the job warns and exits 0 rather than adding a second red job to an already-failed run.

Validated: actionlint + shellcheck and Zizmor 1.28.0 clean; payload dry-run produces valid JSON for both a normal commit and the empty-head_commit tag case.

https://stackstate.atlassian.net/browse/STAC-25533

LouisParkin and others added 2 commits August 6, 2026 11:47
This pipeline has never had a failure notification. Its retired .gitlab-ci.yml
had no notify job and no .cerberus directory, so a broken release branch has
always been silent here. STAC-25510 is what that costs: stackstate-process-agent's
image publishing broke on 2026-07-23 and nobody noticed for 12 days.

Adds a reusable cerberus-notify.yml, structurally identical to the one
stackstate-process-agent gained in STAC-25519, and calls it as a terminal job
from checks-tests.yml.

`action: notify`, never `block`. Blocking locks the branch, additionally
requires the Cerberus GitHub App to be installed here, and mutates the branch
protection pulumi-infra now owns (STAC-25522) -- a later pulumi apply would
silently unlock the branch again.

Push events only, which given the existing `push:` trigger means the release
branch and release tags. Pull request failures already have an owner watching
them, and on a public repo anyone can open a PR that fails on purpose, so
notifying on them would hand the CI channel a spam vector. The condition is
keyed on `github.event_name` rather than a hardcoded ref so the next
release-branch bump only has to touch the `push:` trigger, not two places that
must agree.

Hung off ci-success rather than the individual jobs so there is one funnel for
all failures instead of a notify job per pipeline job.

Two departures from the process-agent original:
  - The header records this as new capability rather than a port.
  - COMMIT_TITLE falls back to the sha. Tag pushes carry no `head_commit`, and
    this workflow runs on them; process-agent's copy is push-to-master only and
    never hits that case.

Both secrets are declared `required: false` and guarded at runtime: a caller
passing `${{ secrets.X }}` for a secret the repo does not hold yields an empty
string, which GitHub rejects against a required secret and fails the call
before the guard can warn. Missing configuration warns and exits 0 rather than
adding a second red job to an already-failed run.

The repo-level secret grant is StackVista/pulumi-infra#277 -- the org copies
are visibility=private and this repo is public. Until that merges this job
warns and passes.

Validated: actionlint (with shellcheck) and Zizmor 1.28.0 clean; payload
construction dry-run produces valid JSON for both a normal commit and the
empty-head_commit tag case.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Phase 2 of the GitLab->GitHub CI migration. The four splunk_* suites and
stackstate_checks_dev need a live Docker daemon, so phase 1 left them out
entirely -- they currently run nowhere.

They cannot run inside the BCI job container. get_docker_hostname() resolves
to `localhost` unless DOCKER_HOST is set, and compose publishes its ports on
the Docker host, so the test process must share the daemon's network
namespace. GitLab avoided this with a docker:dind service whose hostname
resolved identically from both sides; on GitHub the equivalent is to run
directly on the runner. Hence a separate `check-tests-docker` job with no
container and actions/setup-python, rather than extending the existing matrix.

The fixtures pulled their images through registry.tooling.stackstate.io,
which answers 401 from the public internet -- a credential a public repo's
pull_request jobs must never hold. All five paths were /docker/ proxy-cache
entries, so they are repointed at the unambiguous Docker Hub originals via
${SPLUNK_IMAGE}/${VAULT_IMAGE} with public defaults, leaving self-hosted and
local users able to override back to the proxy.

The selector gains a DOCKER_CHECKS set and a third output. splunk_base is a
build dependency of the other three splunk suites, so a change to it fans out
to all four; the reverse does not hold.

setup_artifactory_docker.sh is deliberately not ported -- it existed only to
log Docker in to that proxy.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The five Docker suites failed on their first GitHub run with
`FileNotFoundError: 'docker-compose'`. Compose v1 -- the standalone Python
binary -- reached end of life in July 2023 and is no longer present on the
hosted runner images; they ship v2 as the `docker compose` subcommand. The
GitLab runner image still carried v1, which is why this never surfaced there.

Add `compose_command()`, which prefers `docker compose` and falls back to
`docker-compose`, so developers still on an older toolchain keep working, and
route all four call sites through it. `DOCKER_COMPOSE_COMMAND` overrides the
detection. The result is cached; container-name log checks are untouched,
only the compose-file path changes.

The two test modules shelled out to `docker-compose` directly to set up and
tear down their own fixtures, so they go through the resolver too.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@LouisParkin
LouisParkin requested a review from LouisLotter August 6, 2026 13:51
LouisParkin and others added 5 commits August 6, 2026 15:55
compose_file_active() parsed the human-readable `ps` table, scanning for the
row of dashes that Compose v1 printed between the header and the service
rows. Compose v2 does not emit that separator, so the function returned False
unconditionally and the two remaining stackstate_checks_dev tests failed even
once the command itself resolved correctly.

Use `ps -q` instead: one container id per running service, empty when the
project is down. That output is stable across both generations, so it needs
no version branching.

Verified against a live daemon -- False before up, True after up, False after
down.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
vsphere pinned `vsphere-automation-sdk==1.82.0`, which VMware never published
to public PyPI -- the name is squatted there by an unrelated 0.0.1 placeholder
-- so it was mirrored into the private GitLab package registry and pulled with
a credential.

That credential could not be held safely. A `pull_request` run executes the
pull request's own copy of the workflow and of every script it calls, so a run
holding a secret can always be made to disclose it. The only sound answer was
to withhold it, which meant vsphere did not run on pull requests at all and
was verified only after merge -- a real coverage gap, accepted at the time
because the alternatives cost more.

VMware publishes the same SDK to public PyPI under renamed packages, actively
maintained: pyvmomi, vmware-vcenter, vmware-vapi-runtime and
vmware-vapi-common-client, all at 9.1.0.0. Between them they satisfy every
import the check makes -- pyVmomi/pyVim, vmware.vapi.* and com.vmware.* alike.

So the pin, the credential, the separate job and the coverage gap all go
together:

  - requirements.in names the four public packages
  - fetch_private_wheels.sh is deleted
  - PRIVATE_INDEX_CHECKS, is_private_index() and the private/deferred selector
    outputs are gone; the selector now emits `checks` and `docker_checks`
  - check-tests-private-index is removed and vsphere joins the ordinary matrix,
    so it runs on pull requests like every other suite
  - ci-success loses the private-index arm and the deferral notice
  - vsphere/tox.ini no longer documents a wheelhouse that does not exist

No job in this workflow now has a secret in scope, which is a stronger and much
simpler property to maintain than any arrangement that held one.

Verified: the four pins resolve from public PyPI alone, and the full vsphere
suite passes against them -- 58 passed. actionlint, shellcheck and Zizmor clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
`checksdev validate dep` cross-checks every pin in a check's requirements.in
against agent_requirements.in, the manifest of what the agent embeds. That
file still listed vsphere-automation-sdk, so the four replacement packages
were reported missing from the embedded environment.

Replace the single old entry with the four public ones. Verified locally:
`checksdev validate dep` exits 0, as do config, manifest, metadata and
service-checks.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
STAC-25544: move vsphere to the publicly-published VMware SDK
STAC-25531: run the five Docker-daemon test suites in GitHub Actions
Comment thread .github/workflows/cerberus-notify.yml
@LouisParkin
LouisParkin merged commit 23b7f81 into stackstate-7.78.2 Aug 7, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants