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 _target variant 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 or gh workflow run, optionally with inputs.
workflow_call: the workflow is a reusable workflow and is only started by another workflow that calls it via uses:.
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, mode (default auto), priority (optional; priority rows get chunks of their own, the regular chunks run after them), resume_from_chunk (default 0), chunk_gate (default true), sweep (optional; empty means the run number) |
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 as a serial chain of chunk blocks (each chunk's discover job renders the sweep's 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 sorted to the head of the list and cut into chunks of their own, so every priority row is deployed before the first regular one starts — and deployed in every combination it can take: each variant × each offered mode × Tor and clearnet, in one sweep), mode (default auto), sweep, resume_from_chunk (default 0), chunk_gate (default true), 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.yml: 🚀 Test: Deploy |
Deploys one chunk of the sweep. Every matrix row is a single role#variant carrying the deploy mode the rotation assigned it: swarm rows get a simulated 3-node DinD cluster with an NFS server plus a drain/reschedule state-survival assertion, compose and host rows run the single-node drill. 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, index, sweep (required), whitelist (optional; explicit value wins over diff), priority, lifecycles, modes (default auto), filesystem, tor, marker |
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.