The hourly sweep fought the rest of the CI control plane instead of helping it: it preempted itself (17 of the last 29 runs concluded cancelled 1-2s after their successor was created, for 8s of work behind a 74-80min queue wait) and shipped MAX_ATTEMPTS=0, which the script reads as no ceiling while its own README promised the opposite. The 24h age cutoff could not bound it either, because every rerun refreshes the run's updatedAt and so keeps it inside the window. Removes the workflow, the two scripts it was the sole consumer of, its unit test, and the CI_RERUN_* documentation that would otherwise point at a deleted file. The workflow is disabled in both origin and fork so no sweep fires before this lands. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
15 KiB
GitHub Actions 🎬
This page catalogs every GitHub Actions workflow defined under the workflows directory. It lists each workflow together with a short description, its triggers, and the inputs it accepts.
For the CI flow (orchestrator stages, gates, fork-PR handling) see pipeline.md. For the repository variables that control CI behaviour see configuration.md. For the naming and shell-extraction conventions that every workflow file MUST follow see workflow.md. For the branch-prefix scopes referenced by the PR entry workflow see branch.md. For the mirror architecture referenced by the image workflows see mirror.md.
What GitHub Actions are 📘
GitHub Actions is GitHub's built-in CI/CD system. Each YAML file under .github/workflows/ is one workflow; a workflow contains one or more jobs, and each job runs a sequence of steps on a hosted or self-hosted runner. Workflows are started by triggers declared in the on: section. The most common triggers in this repository are:
push: fires when commits land on a branch.pull_request/pull_request_target: fires on PR lifecycle events (opened,synchronize,reopened,ready_for_review,closed,converted_to_draft). The_targetvariant runs with the base-branch secrets and is used to grant fork PRs controlled access to privileged steps.schedule: cron-based periodic runs (UTC).workflow_dispatch: manual run from the GitHub UI orgh workflow run, optionally with inputs.workflow_call: the workflow is a reusable workflow and is only started by another workflow that calls it viauses:.delete: fires when a branch or tag is deleted.
Workflows communicate through inputs (on workflow_call / workflow_dispatch), outputs, concurrency groups (which cancel or serialize runs with the same group key), and the GITHUB_TOKEN / repository secrets and variables. The entry points of this repository (entry-*.yml) translate external triggers into a call to the central call-orchestrator.yml. Most other workflows are reusable building blocks invoked from the orchestrator.
Workflow catalog 📚
Trigger column legend: auto = fires automatically (push, pull_request, schedule, delete); manual = workflow_dispatch; reusable = workflow_call. Multiple values mean the workflow accepts any of them.
Entry points 🚪
| Workflow | Description | Trigger | Inputs |
|---|---|---|---|
entry-pr-change-orchestrate.yml: 🔀 Pull Request |
Detects PR scope from changed files + branch prefix, then conditionally calls the orchestrator. A maintainer 🛡️ Trusted label builds the privileged images from the PR head — see pipeline.md. A 🧩 Subset label pins the deploy matrix to the roles listed in the PR body — see pipeline.md. |
auto (pull_request & pull_request_target: opened, synchronize, reopened, ready_for_review, labeled) |
none |
entry-push-latest.yml: 📤 Push |
Syncs main from the configured source repository, then runs the orchestrator on pushes to main, feature/**, hotfix/**, fix/**, chore/**, alert-autofix-*; on tagged main it also calls call-release-version.yml. Respects the CI_CANCEL_IN_PROGRESS, CI_SYNC_MAIN_SOURCE_REPOSITORY, and CI_RUN_ON_MAIN repository variables, see configuration.md. |
auto (push) |
none |
entry-manual-steer.yml: 🕹️ Manual |
Manual dispatch of the full orchestrator for a chosen distro set and app whitelist. The whitelist input accepts the __ALL__ sentinel for forced full deploy; see the "Diff-driven app selection" subsection in pipeline.md. |
manual | distros (default debian), whitelist (optional; __ALL__ forces full deploy, empty triggers diff derivation, any other value is verbatim), lifecycles, modes (default swarm compose), priority (optional; priority line first, regular line runs the rest after it succeeds) |
entry-pr-closed-cancel-workflows.yml: 🚫 Cancel: PR Runs on Close |
Cancels active workflow runs for a PR when it is closed or converted to draft. | auto (pull_request_target: closed, converted_to_draft) |
none |
entry-delete-branch.yml: 🚫 Cancel: Runs on Branch Delete |
Enters the push-entry concurrency group for the deleted branch so that any in-flight run on it is cancelled; a fallback step cancels remaining runs via the API. | auto (delete) |
none |
Orchestration 🎵
| Workflow | Description | Trigger | Inputs |
|---|---|---|---|
call-orchestrator.yml: 🎵 CI: Orchestrator |
Central coordinator. Runs fork-prereq wait, security, linting, CI image build, code tests, code-quality gate, DNS tests, mirror, deploy tests (optionally split into a priority line and a regular line via priority; each mode's discover job renders its own plan table via cli.meta.ci.plan into the run summary), install tests, test-workspace, test-instructions, final done gate. |
reusable | distros (required), whitelist (optional), priority (optional; app ids deployed first per mode, then excluded from the regular line, which only starts after every priority job succeeded), image_wait_attempts (default 1980), image_wait_sleep_seconds (default 10), workspace (default auto), instructions (default auto) |
Security and linting 🛡️🔍
| Workflow | Description | Trigger | Inputs |
|---|---|---|---|
cron-security-codeql.yml: ⏰ Scan: CodeQL (Advanced) |
CodeQL static analysis. Invoked by call-orchestrator.yml so every CI run produces a single scan; additionally runs on a weekly cron so coverage does not drop when no pushes land on main. See pipeline.md for the gating behaviour. |
reusable, auto (schedule: weekly Mon 00:00 UTC) |
none |
call-lint.yml: 🧹 Lint |
Runs make lint (every lint check in parallel: action, ansible, javascript, makefile, markdown, mermaid, packages, playwright, python, shellcheck) plus a hadolint SARIF job on Dockerfile. |
reusable, manual | none |
CI images 🐳
| Workflow | Description | Trigger | Inputs |
|---|---|---|---|
call-images-build-ci.yml: 🖼️ Build: CI Images (all distros) |
Builds the per-distro CI base images consumed by all test jobs. | reusable | distros (required), checkout_ref (optional), image_tag (default ci-${github.sha}), concurrency_channel (default default) |
cron-images-cleanup-ci.yml: ⏰ Images: Cleanup CI (GHCR) |
Deletes CI images from GHCR older than N days. | auto (schedule: weekly Mon 00:00 UTC), manual |
days (default 7) |
Image mirroring 🪞
| Workflow | Description | Trigger | Inputs |
|---|---|---|---|
call-images-mirror-missing.yml: 🪞 Mirror: Docker Hub → GHCR (only missing) |
Mirrors only the upstream images that are not yet in GHCR. Called from the orchestrator before deploy tests. | reusable | ghcr_namespace, ghcr_prefix (default mirror), repo_root (default .), source_repository, source_ref, plus throttling knobs |
cron-images-mirror-all.yml: ⏰ Mirror: Docker Hub → GHCR |
Full nightly mirror of every referenced upstream image into GHCR. | auto (schedule: daily 00:00 UTC), manual |
ghcr_namespace, ghcr_prefix (default mirror), repo_root (default .), images_per_hour (throttle) |
entry-manual-mirror-cleanup.yml: 🧹 Images: Cleanup GHCR (Private) |
Deletes GHCR mirror packages by prefix and visibility. Supports dry_run. |
manual | ghcr_namespace, ghcr_prefix (default mirror), visibility (private/public/internal, default private), dry_run |
Code tests 🧪
| Workflow | Description | Trigger | Inputs |
|---|---|---|---|
call-test.yml: 🧪 Test |
Runs make test (unit, integration, lint and external tests in parallel) on the runner host. |
reusable, manual | none |
Infrastructure tests 🌐📦💻📥
| Workflow | Description | Trigger | Inputs |
|---|---|---|---|
call-test-dns.yml: 💬 Test: DNS |
Validates DNS resolution across target distributions. | reusable, manual | distros (required on call; default debian on manual) |
call-test-deploy-single-node.yml: 🏝️ Test: Deploy (single-node) |
Single point of truth for the non-swarm deploy tests: fans out to call-test-deploy-compose.yml and call-test-deploy-host.yml, gated per mode via the modes input. Called from the orchestrator. |
reusable | distros (required), whitelist, lifecycles, modes (default compose host), blacklist (optional; app ids dropped from discovery) |
call-test-deploy-compose.yml: 📦 Test: Deploy (compose) |
Deploy test (compose mode) across all deployment types (INFINITO_DISCOVER_ALL; lifecycle-filtered to the INFINITO_LIFECYCLES envelope, so server/universal/workstation scopes but not just web-*). When whitelist is empty, the discover job derives one from the branch's diff vs origin/main; see the "Diff-driven app selection" subsection in pipeline.md. |
reusable | distros (required), whitelist (optional; explicit value wins over diff), lifecycles, blacklist (optional) |
call-test-deploy-host.yml: 🖥️ Test: Deploy (host) |
Deploy test (host mode) for invokable non-stack roles that configure the host instead of shipping a container stack. Same diff-driven whitelist resolution as call-test-deploy-compose.yml; no Playwright stage (host roles have no web UI). |
reusable | distros (required), whitelist (optional; explicit value wins over diff), lifecycles, blacklist (optional) |
call-test-deploy-swarm.yml: 🐝 Test: Deploy (swarm) |
Deploy test (swarm mode) across the full application matrix; each app gets a simulated 3-node DinD cluster with an NFS server, then a drain/reschedule state-survival assertion. Same diff-driven whitelist resolution as call-test-deploy-compose.yml. |
reusable, manual | distros (required), whitelist (optional; explicit value wins over diff), lifecycles, blacklist (optional; reusable trigger only) |
call-test-instructions.yml: 📖 Test: Instructions |
Extracts the ### Production command from a role README (a random role when role is empty) and executes it against the runner: <your-server> becomes localhost (ansible_connection local) and the Docker socket replaces the TTY flag. Verifies the documented one-command deploy actually works, seeding the run´s freshly built CI image (needs call-images-build-ci.yml) instead of the published default. Gates the final done job. |
reusable, manual | distros (required), role (optional; empty picks one at random), priority (optional), whitelist (optional) |
call-test-install-make.yml: 📥 Test: Install Make |
Validates the make install entry points. |
reusable | none |
call-test-install-pkgmgr.yml: 📥 Test: Install Package Manager |
Validates installation via the upstream package manager. | reusable | none |
call-test-workspace.yml: 💻 Test: Workspace |
Builds and exercises the dev-runtime image matrix. | reusable, manual | none |
Release and maintenance 🚀🔄
| Workflow | Description | Trigger | Inputs |
|---|---|---|---|
call-release-version.yml: 🚀 Release: Version Logic |
Releases a specific version tag (build + publish). Called from entry-push-latest.yml on tagged pushes. |
reusable, manual | tag (required, e.g. v1.2.3) |
cron-release-highest.yml: ⏰ Release: Highest Missing Version |
Scheduled backfill: finds the highest tag without a release and triggers call-release-version.yml for it. |
auto (schedule: daily 00:00 UTC), manual |
none |
cron-cleanup-stale.yml: ⏰ Cleanup: Stale Repository Data |
Marks and closes stale issues and PRs, deletes inactive branches, and prunes old GHCR CI image versions. | auto (schedule: daily 00:00 UTC), manual |
none |
cron-update.yml: ⏰ Update: Versions |
Updates Docker image versions and other pinned dependencies; opens an update PR via a GitHub App installation token so PR-lifecycle events fire on the resulting PR. Both jobs are gated behind the CI_ENABLE_AUTO_UPDATES repository variable, see configuration.md. Requires the BOT_APP_CLIENT_ID and BOT_APP_PRIVATE_KEY repository secrets, see secrets.md. |
auto (push to main, schedule: daily 00:30 UTC), manual |
none |
entry-pr-open-dependabot-close.yml: 🚫 Dependabot: Close while auto-updates disabled |
Auto-closes Dependabot PRs while CI_ENABLE_AUTO_UPDATES is not set to true, so Dependabot honours the same gate as the workflow-driven update jobs. See configuration.md. |
auto (pull_request_target: opened, reopened) |
none |
Changing workflows ✍️
Before adding or editing a workflow file:
- Follow the naming schema and shell-extraction rules in workflow.md.
- If the change affects the CI flow (stages, gates, order), also update pipeline.md.
- If the change adds or removes a repository variable, also update configuration.md.
- Update the relevant row in this page so the catalog stays accurate.