Skip to content

Continuous integration and develop publishing

This page covers ci.yml, runner-compatibility.yml, develop.yml, the fork pull request policy, and gate troubleshooting. Release and publish workflows are in Releases; security scans are in Security scanning.

ci.yml

Purpose:

  • run the repository test suite for all branches and pull requests

Triggers:

  • push to any branch (tags do not start it)
  • pull request targeting any branch

Behavior:

  • fails early on fork pull requests that do not carry the approved-for-ci label
  • uses ./.github/actions/suite-tests to set up Python, Go, and Lua (installed through APT), sync the Python workspace, and run the suite; the enable_cache: true input controls only the uv dependency cache — the action always runs with the Go cache off
  • runs tests with make test
  • builds the documentation with make build-docs. The build is strict, so a broken link, a broken anchor, or a page missing from the navigation fails the job; make build-docs checks the navigation first and then runs the Zensical build. It reuses the uv environment that suite-tests set up
  • summarizes the test and documentation-build commands and the final job status

Permissions:

  • top-level contents: read

runner-compatibility.yml

Purpose:

  • check the repository test suite on the pinned Ubuntu image and the next Ubuntu image

Triggers:

  • weekly schedule (30 3 * * 1)
  • manual dispatch

Behavior:

  • runs the shared repository test action on ubuntu-24.04 and ubuntu-26.04
  • keeps both matrix jobs independent: one image failing does not cancel the other (fail-fast: false)
  • uses no secrets and has read-only contents permission
  • writes a summary for each matrix job

develop.yml

Purpose:

  • publish develop-tagged images and the <VERSION>-develop Helm chart after the CI workflow passes for the same commit on the develop branch. The Security workflow is advisory and does not block publishing

Triggers:

  • workflow_run: the CI workflow completes for the develop branch

Each completed CI run starts the workflow. The check-gate job supplies the condition that CI passed for the commit.

Behavior:

  • does not run the tests again; ci.yml and security.yml already run on each push to develop
  • the check-gate job runs only if the triggering run passed, was started by a push to develop, and came from this repository (not from a fork branch named develop)
  • check-gate runs on ubuntu-24.04 with actions: read and contents: read. It checks out the tested commit (workflow_run.head_sha, no persisted credentials) and loads ./.github/actions/check-develop-gate from that checkout. It reads no secrets
  • check-gate reads, through the GitHub API, the latest push run of ci.yml for the commit on develop in this repository. The run must be completed with the conclusion success. A newer failed or unfinished run takes precedence over an older successful run
  • check-gate also makes sure that the commit is still the head of develop. A late result for an older commit thus does not overwrite a newer develop image
  • if a check fails, check-gate writes the reason as a notice and the publish job is skipped. The completion of the other workflow starts a new check. If the API request fails, check-gate fails
  • a concurrency group for each commit stops two runs from publishing the same commit at the same time
  • the build-push-dev job runs only when check-gate reports ready
  • build-push-dev uses the develop-publish concurrency group, so only one publish runs at a time. A build takes minutes, and a newer commit can pass check-gate in that time. The newer run waits until the active publish completes. While a publish runs, GitHub keeps only the newest waiting run and cancels older waiting runs
  • right after its first step checks out the tested commit (workflow_run.head_sha), build-push-dev runs the same check again. If the commit is no longer the head of develop, all other steps are skipped. The newest commit is thus always published last
  • uses the Ubuntu runner arc-dind-pet-vsphere-prod in pet-privileged-runners
  • uses ./.github/actions/prepare-publishing to install GNU Make when needed, resolve credentials, and log in to Docker and Helm
  • uses the provided ECMWF container registry (ECCR) credentials when both values are set; otherwise, retrieves credentials from Vault and keeps each provided value in preference to its Vault value
  • validates and masks the resolved credentials, then passes action outputs to Docker and Helm without exporting credentials to the job environment
  • publishes images and the Helm chart with make publish-develop
  • summarizes the CI gate result, head recheck, publishing target, and final job status

GitHub reads workflow_run workflows only from the default branch. Changes to develop.yml have an effect only after they are merged into main.

Permissions:

  • top-level contents: read
  • check-gate: actions: read and contents: read
  • build-push-dev: actions: read for the gate recheck, contents: read for checkout, and id-token: write for Vault authentication

Credential inputs:

  • ECCR_USERNAME
  • ECCR_PASSWORD

The credential action accepts repository secrets. It does not read repository variables. If either value is missing, it uses Vault with GitHub OpenID Connect (OIDC) authentication. Both resolved values must be set before registry login.

Gate troubleshooting

The shared gate action writes Starting the CI gate. before it loads the gate module. It then logs each API check: the branch head, and the CI push runs. The Release workflow uses the same action for main.

A notice that starts with Publishing is blocked is not an action failure. It means that the required CI run has not passed for the branch head commit, or the commit is no longer the branch head. The gate returns ready: false, and publishing is skipped.

A module-load or API error fails the action and sets no ready output. The error identifies the operation and includes the HTTP status when available. For an HTTP 403 response from the workflow-runs API, check that the calling job has actions: read. Both Develop gate calls need this permission.

If the log has only the action inputs and no startup message, inspect the job annotations and runner logs. The gate code might not have started. Do not change the publishing conditions to bypass the failure. Merge changes to the default branch (main) before testing a new workflow_run run; a rerun of an old run does not verify the new workflow revision.

Fork pull request policy

The repository does not use pull_request_target.

Instead, workflows that execute PR code enforce a label-based gate for fork pull requests:

  • if a PR comes from a fork and does not have the approved-for-ci label, the workflow fails early
  • security.yml starts a new run when the label is applied, because it listens for the labeled event
  • ci.yml uses the default pull-request event types, so re-run that workflow after you apply the label

This policy currently applies to:

  • ci.yml
  • all jobs in security.yml