Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions docs/developers-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,55 @@ def test_uses_pinned_full_sha(caller_step):
If a workflow's behaviour genuinely depends on a feature only present from a
particular commit onwards, express that as a comment or a changelog note, not
as a test assertion on the SHA string.

## Mutation-testing workflow contract tests

This repository runs scheduled, informational mutation testing through a thin
caller workflow, [`.github/workflows/mutation-testing.yml`](../.github/workflows/mutation-testing.yml),
which delegates to the shared reusable workflow
`leynos/shared-actions/.github/workflows/mutation-cargo.yml`. The heavy
lifting — running `cargo-mutants`, sharding, and summarizing survivors —
lives in `shared-actions`; this repository carries only declarative
configuration. The run is **informational only**: it never gates a pull
request. Survivors are reported through the job summary and downloadable
artefacts so they can be triaged into tests, not enforced as a blocking
check.

The workflow runs in two modes. A **daily schedule** (09:20 UTC) fires a
change-scoped run that mutates only the source files touched within the
detection window, so quiet days are cheap no-ops. A **manual dispatch** (the
Actions "Run workflow" control) mutates the whole crate; select a branch in
that control to exercise a feature branch.

The caller passes a small set of configuration inputs, each carrying intent:

- `extra-args` — `--all-features`, so the mutation run mirrors the CI test
baseline; a mismatch would report feature-gated code as untested.
- `exclude-globs` — `src/tests/**,tests/support/**,src/bin/bless_traces.rs`,
keeping the re-exported test module, test-support helpers, and the
manually run golden-snapshot regenerator out of the survivors table, since
none of them is guarded by the test suite.

The `uses:` reference pins the shared workflow to a full 40-character commit
SHA rather than a branch or tag, so a force-push upstream cannot silently
change what runs here. The contract test asserts only that the pin is a full
commit SHA, not a particular value, so Dependabot bumps it automatically
without any accompanying test edit.

Because the caller is configuration rather than code, a contract test in
`tests/workflow_contracts/mutation_testing_test.py` pins the shape it must
uphold, failing the pull request when the caller drifts — repointing the pin
at a branch, widening the token scope, or dropping a configuration input —
rather than letting the breakage surface only in a scheduled run. Run it
locally with `make test-workflow-contracts`. The test validates:

- the `uses:` reference targets `mutation-cargo.yml` pinned to a full commit
SHA;
- the `with:` block carries exactly the expected `extra-args` and
`exclude-globs` configuration;
- job permissions are least-privilege (`contents: read`, `id-token: write`)
and the workflow-level default token scope is empty;
- `concurrency` serializes runs per ref without cancelling one in progress;
and
- the triggers keep the daily schedule and a plain `workflow_dispatch` with
no legacy branch input.
Loading