Add scheduled mutation testing to generated repos - #52
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds a generated GitHub Actions workflow for scheduled or manually dispatched mutation testing through a shared reusable workflow. Documents the workflow and extends generated tooling contracts to validate permissions, inputs, wiring, pins, and setup commands. ChangesMutation testing workflow and contracts
Sequence Diagram(s)sequenceDiagram
participant Trigger as GitHub schedule or dispatch
participant Caller as mutation-testing.yml
participant Shared as mutation-cargo workflow
participant Runner as cargo-mutants
Trigger->>Caller: start workflow
Caller->>Shared: pass --all-features and setup commands
Shared->>Runner: execute mutation testing
Possibly related issues
Possibly related PRs
Poem
Caution Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional.
❌ Failed checks (1 error, 1 inconclusive)
✅ Passed checks (18 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5cb3aa8dbe
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Review feedback addressed in facc38a: the generated
Re-validated: |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@template/.github/workflows/mutation-testing.yml`:
- Around line 1-47: The workflow contract for mutation testing is not covered by
assertions, so changes to the pinned reusable-workflow SHA, the setup package
list, or the job permissions could slip through. Extend the existing
tooling-contract tests around mutation-testing.yml to verify the job uses the
expected pinned ref in the mutation job, the setup-commands installs the
required packages, and the mutation job permissions remain scoped to contents:
read and id-token: write.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 27643c2a-2103-4b4a-9c4f-1d5db8d3a601
📒 Files selected for processing (2)
template/.github/workflows/mutation-testing.ymltemplate/docs/repository-layout.md.jinja
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai resume |
✅ Action performedReviews resumed. |
22644be to
593679c
Compare
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/helpers/tooling_contracts/workflows.py`:
- Around line 354-371: Update the apt-get install extraction loop to skip lines
whose trimmed content begins with “#”, so commented commands are never treated
as installs. In the existing shlex.split error handler, stop extraction by
raising or otherwise propagating the parsing failure instead of falling back to
segment.split(); preserve normal token filtering for valid shell commands.
- Around line 381-395: Update the mutation-testing workflow assertions in the
contract test to require a schedule entry with cron exactly "15 9 * * *" and
require concurrency.group to equal "mutation-testing-${{ github.ref }}". Keep
the existing checks for schedule presence, workflow_dispatch, and
cancel-in-progress unchanged.
- Around line 27-31: Replace the text-search regexes in
tests/helpers/tooling_contracts/workflows.py lines 27-31 with full-reference
patterns suitable for re.fullmatch(), then update the checks at lines 244-247,
286-289, and 443-446 to parse the relevant job steps and validate each actual
uses: value via re.fullmatch(). Ensure comments or mutable refs cannot satisfy
the setup-rust, setup-python, or upload-artifact contract checks.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 16167a73-1adb-4c69-929e-403a112dae5e
📒 Files selected for processing (10)
docs/developers-guide.mddocs/users-guide.mdtemplate/.github/workflows/mutation-testing.ymltemplate/docs/developers-guide.md.jinjatemplate/docs/repository-layout.md.jinjatemplate/docs/users-guide.md.jinjatests/helpers/tooling_contracts/orchestration.pytests/helpers/tooling_contracts/workflows.pytests/test_helpers.pytests/test_template/test_tooling_contracts.py
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
leynos/whitaker(auto-detected)
|
@coderabbitai review |
Add a mutation-testing caller workflow to the template so newly generated Rust projects run scheduled mutation testing by default. The workflow is a thin caller of the shared mutation-cargo reusable workflow in leynos/shared-actions, pinned to a full commit SHA in line with the template's action-pinning convention. The workflow runs daily at 09:15 UTC with a comment advising maintainers to stagger the slot per repository, and supports manual dispatch. It defaults the token to no scopes, with the job opting in to contents: read and id-token: write. The extra-args input mirrors the CI test baseline (--all-features); workspace inputs are omitted as the generated project is a single crate. The file is plain YAML rather than Jinja-templated, matching ci.yml and act-validation.yml, as it needs no template variables. The generated repository-layout document is updated to list the new workflow.
The generated .cargo/config.toml links Linux dev targets with clang and -fuse-ld=mold, and the generated ci.yml installs mold before any cargo command, but the mutation workflow's mutants jobs had no way to install it, so the cargo-mutants baseline would fail to link on a bare ubuntu-latest runner. Bump the shared workflow pin to 0c8bd605f8966a004decb0b54f717a745f51bc57, which introduces the setup-commands input, and use it to install clang, lld, and mold exactly as the generated ci.yml does. The install is unconditional, matching ci.yml's own convention: CI always runs on Linux runners, and ci.yml installs the packages regardless of the dev_target chosen at generation time, so the workflow stays a plain copied file rather than becoming Jinja-templated.
The mutation-testing.yml caller shipped without any contract coverage, so a regression to the reusable-workflow reference, the setup-command package list, or the mutation job's permission scope could slip through review. Extend the rendered tooling-contract suite to parse mutation-testing.yml and assert that: root permissions grant no scopes; the mutation job calls the shared mutation-cargo reusable workflow; the job permissions stay scoped to contents: read and id-token: write; extra-args mirrors the CI --all-features baseline; and the setup-commands install clang, lld, and mold via apt-get. The pinned reusable-workflow SHA is deliberately not asserted, as Dependabot owns and bumps that reference independently of this contract. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
repository-layout listed the generated mutation-testing.yml workflow, but neither user guide explained what it does or how it affects a generated project, leaving adopters without guidance. Add a "Scheduled Mutation Testing" section to both the template-rendered user guide (template/docs/users-guide.md.jinja) and the parent-repository user guide (docs/users-guide.md). The section explains that generated projects run cargo-mutants via the shared mutation-cargo reusable workflow on a daily schedule plus manual dispatch, what surviving mutants mean, that scheduled runs mutate only recently changed files while dispatch runs cover the whole crate, and that the runs are informational rather than gating pull requests. It also tells adopters to stagger the cron slot and notes the least-privilege token scope. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The mutation-testing contract only checked root/job permissions, the reusable-workflow path prefix, extra-args, and substring package matches, so several workflow regressions could still pass: an un-pinned reusable ref, a dropped schedule or manual dispatch, a flipped cancel-in-progress, or a package name appearing only in a comment. Extend `_assert_mutation_workflow_contracts` to also require: - an `on.schedule` cron trigger and `workflow_dispatch` support; - `concurrency.group` present with `cancel-in-progress: false`, so queued runs wait rather than cancelling; - the mutation job's `uses` ref pinned to a full 40-character commit SHA (format only; the specific SHA is owned by Dependabot and not hard-coded, so the contract survives dependency bumps); - clang, lld, and mold present as complete `apt-get install` arguments, parsed from the extracted install command rather than substring-matched against the whole setup script. Collapse the helper's docstring to a single-line summary matching its sibling `_assert_*` workflow validators. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The user guides describe the scheduled mutation-testing workflow, but the developer guides omitted it, leaving contributors without pointers to how it is tested or maintained. Add a note to the parent developer guide (docs/developers-guide.md) recording that the template renders the mutation-testing workflow into generated projects, that its rendered contract is asserted by `_assert_mutation_workflow_contracts`, and that Dependabot owns the pinned reusable-workflow SHA (so the test asserts the pin format, not a hard-coded value). Add a companion note to the generated-project developer guide (template/docs/developers-guide.md.jinja) explaining that the scheduled workflow runs cargo-mutants via the shared reusable workflow, is informational rather than a pull-request gate, has its pinned SHA kept current by Dependabot, and that surviving mutants should be promoted into new tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dependabot bumps the pinned GitHub Actions commit SHAs in the template's workflow files, but it cannot update the contract tests, so hard-coding those SHAs in assertions made the suite drift and fail on every bump. Assert action pins by format instead of by value. Two helpers, `_assert_pinned_to_commit_sha` (for a parsed `uses` field) and `_assert_pinned_action_in_text` (for a whole-workflow substring search), require each action reference to target its expected path pinned to a full 40-character commit SHA, without naming the SHA. Apply them to the shared coverage, setup-rust, setup-python, upload-artifact, and mutation-cargo references, and route the mutation-job pin check through the shared helper. Replace the `_ci_workflow` fixture's real SHA with a 40-zero placeholder. The release workflow's `CROSS_REVISION` pin is left asserted verbatim: it is a `cargo install cross --rev` git revision, not a GitHub Actions `uses:` SHA, and Dependabot does not manage it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The mutation-testing and pinned-action contract checks were satisfiable by
non-runnable or mutable inputs: comment-only or malformed apt installs
passed the package check, text-searched action pins could match a commented
or otherwise non-step reference, and the schedule/concurrency checks only
confirmed a cron and group existed rather than the exact daily per-ref
behaviour.
Parse the actual workflow steps and validate each `uses:` value with
`re.fullmatch` via a new `_assert_pinned_step_uses` helper (plus
`_iter_job_steps` for cross-job release steps), replacing the raw-text
searches for the setup-rust, setup-python, and upload-artifact pins so a
comment or mutable tag can no longer satisfy them. Make
`_extract_apt_install_packages` skip commented lines and raise on `shlex`
parse failures instead of masking malformed shell as a valid install.
Assert the exact cron (`15 9 * * *`) and concurrency group
(`mutation-testing-${{ github.ref }}`) for the mutation-testing workflow.
Add focused unit tests for the tightened apt-install parser covering
normal extraction, comment skipping, and malformed-shell rejection.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rebasing onto main brought in the scheduled dependency-audit workflow contract (`_assert_audit_workflow_contracts` and its `_is_pinned_action` helper), which referenced the `_SETUP_RUST_USES_TEXT_RE` constant that this branch had renamed to `_SETUP_RUST_USES_RE` when switching the pinned-action checks to parse job steps and `re.fullmatch`. Point the audit contract at the renamed constant so both the audit and mutation-testing contracts share one setup-rust pattern. Also tidy merge artefacts: sort the workflows helper imports, drop a duplicate module docstring stranded in the test module by the three-way merge, and apply `ruff format` so `make check-fmt` passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
18d169c to
52d1927
Compare
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
tests/test_helpers.py (1)
173-201: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winSplit the multi-branch ref generator.
Extract the four
kindbranches into focused helpers or predicates; this conditional exceeds the two-branch limit.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/test_helpers.py` around lines 173 - 201, Refactor _non_sha_refs so it no longer contains the four-way kind match. Extract the short, long, uppercased, and branch generation paths into focused helper strategies or predicates, then compose them in _non_sha_refs while preserving the guarantee that generated refs are not 40-character lowercase-hex SHAs.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/helpers/tooling_contracts/workflows.py`:
- Around line 508-516: Update the mutation-testing workflow contract assertions
around require_mapping so the trigger mapping contains exactly the schedule and
workflow_dispatch keys, rejecting any additional push or pull-request triggers
while preserving the existing cron and manual-dispatch checks.
---
Outside diff comments:
In `@tests/test_helpers.py`:
- Around line 173-201: Refactor _non_sha_refs so it no longer contains the
four-way kind match. Extract the short, long, uppercased, and branch generation
paths into focused helper strategies or predicates, then compose them in
_non_sha_refs while preserving the guarantee that generated refs are not
40-character lowercase-hex SHAs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 6e28f6ee-2f29-49ca-97a8-a97f7090e1b3
📒 Files selected for processing (10)
docs/developers-guide.mddocs/users-guide.mdtemplate/.github/workflows/mutation-testing.ymltemplate/docs/developers-guide.md.jinjatemplate/docs/repository-layout.md.jinjatemplate/docs/users-guide.md.jinjatests/helpers/tooling_contracts/orchestration.pytests/helpers/tooling_contracts/workflows.pytests/test_helpers.pytests/test_template/test_tooling_contracts.py
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
leynos/whitaker(auto-detected)
Tighten the mutation-testing workflow contract to require the trigger
mapping to be exactly {schedule, workflow_dispatch}, so an added push or
pull-request trigger is rejected rather than silently accepted; the exact
cron and manual-dispatch checks are preserved. This mirrors the audit
workflow contract's trigger assertion.
Refactor the `_non_sha_refs` Hypothesis strategy to drop its four-way
`match kind` block. Extract focused strategies for too-short and too-long
hex refs, branch names, and uppercased 40-character hex refs, then compose
them with `st.one_of`, preserving the guarantee that generated refs are
never a 40-character lowercase-hex commit SHA.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The `_extract_apt_install_packages` shell parser handled many input shapes (flags in any position, comment lines, backslash continuations) but was only exercised by example tests, leaving its invariant implicit. Add Hypothesis strategies for shell-safe package and flag tokens and three property tests: one asserts the parser returns exactly the non-flag arguments in order for an install line of interleaved flags and packages (with varied indentation and optional sudo); one asserts a commented install line never contributes packages; and one asserts packages split onto a backslash-continued line are still recovered. The prior example tests, including the exact-template form and the malformed-shell rejection, remain as concrete anchors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@coderabbitai Have the following now been resolved? tests/test_helpers.py (1)
🤖 Detailed instructionsVerify each finding against current code. Fix only still-valid issues, skip the In Source: Path instructions |
|
@coderabbitai Have the following failed checks now been resolved? If further work is required, please provide an AI agent prompt for the remaining work to be done to address these failures. Do not treat warnings as optional or aspirational. Where a change is out of scope for this PR, propose a GitHub issue unless one exists already. (Treat documentation and validation coverage as in scope). ❌ Failed checks (1 error, 1 warning)
|
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
ast-grep outline tests/test_helpers.py --items all --type function --match 'non_sha|ref' || true
printf '\n--- _non_sha_refs references ---\n'
rg -n -C 5 '\b_non_sha_refs\b' tests/test_helpers.py
printf '\n--- requested source range ---\n'
sed -n '150,225p' tests/test_helpers.pyLength of output: 4806
Static verification completed; no repository tests were executed in this inspection environment. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '== Recent commits =='
git log --oneline -12
printf '%s\n' '== Workflows helper outline =='
ast-grep outline tests/helpers/tooling_contracts/workflows.py --items all --type function
printf '%s\n' '== Relevant workflow contract implementation =='
rg -n -A100 -B20 \
'def _assert_mutation_workflow_contracts\b|def _extract_apt_install_packages\b' \
tests/helpers/tooling_contracts/workflows.py
printf '%s\n' '== Helper-test outline =='
ast-grep outline tests/test_helpers.py --items all --type function --match 'extract|non_sha'
printf '%s\n' '== Parser tests and property-test evidence =='
rg -n -A40 -B15 \
'extract_apt_install_packages|`@given`|hypothesis|non_sha_refs' \
tests/test_helpers.py tests
printf '%s\n' '== Current mutation workflow =='
cat -n template/.github/workflows/mutation-testing.ymlLength of output: 84073
Use this prompt for the remaining work: No GitHub issue is needed: the remaining change is in scope and narrowly scoped to this PR. |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
tests/helpers/tooling_contracts/workflows.py (3)
457-471: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winReduce private helper docstrings to one-line summaries.
tests/helpers/tooling_contracts/workflows.py#L457-L471: Replace the structured_extract_apt_install_packagesdocstring with a concise summary.tests/helpers/tooling_contracts/workflows.py#L635-L643: Replace the explanatory_assert_pinned_step_usesdocstring with a concise summary.As per path instructions, “Use a single-line summary for private functions and methods.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/helpers/tooling_contracts/workflows.py` around lines 457 - 471, Shorten the private helper docstrings to single-line summaries: replace the structured docstring for _extract_apt_install_packages in tests/helpers/tooling_contracts/workflows.py at lines 457-471 with one concise description, and do the same for _assert_pinned_step_uses at lines 635-643. Preserve each helper’s purpose while removing parameter, return-value, and explanatory sections.Source: Path instructions
513-517: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winRequire exactly the documented schedule entry.
Replace the existential check with equality to
[{ "cron": _MUTATION_CRON }]. The current assertion accepts extra schedules or extra entry fields, so the daily trigger contract can drift while remaining green.Proposed fix
- assert any( - isinstance(entry, dict) and entry.get("cron") == _MUTATION_CRON - for entry in schedule - ), f"expected mutation-testing workflow to schedule cron {_MUTATION_CRON!r}" + assert schedule == [{"cron": _MUTATION_CRON}], ( + "expected mutation-testing workflow to contain exactly the documented " + f"schedule cron {_MUTATION_CRON!r}" + )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/helpers/tooling_contracts/workflows.py` around lines 513 - 517, Update the schedule assertion in the workflow contract test to compare schedule directly with a single-entry list containing only {"cron": _MUTATION_CRON}, replacing the any-based existential check. Preserve the existing require_sequence lookup and failure message context while rejecting extra schedules or fields.
472-498: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winParse an actual
apt-get installcommand.Tokenize the complete logical command and require optional
sudofollowed by exactapt-get,installtokens before extracting packages.line.find()accepts text such asecho "apt-get install clang lld mold", allowing the contract to pass without a runnable installation command. Add that negative case.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/helpers/tooling_contracts/workflows.py` around lines 472 - 498, Update the setup-command parsing logic around the apt-get marker to tokenize each complete logical shell command, then require the command structure to be optional sudo followed by exact apt-get and install tokens before extracting package names. Do not match embedded text such as echo arguments, and add a negative test covering an echo containing “apt-get install” without an actual installation command.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/test_helpers.py`:
- Around line 175-198: Annotate the module-level Hypothesis strategy aliases
with explicit SearchStrategy types: update _non_sha_refs at
tests/test_helpers.py lines 175-198 and _apt_package_tokens, _apt_flag_tokens,
and _apt_install_tokens at lines 618-634. Use the appropriate element type for
each strategy so all aliases remain statically type-checked without changing
their generated values.
---
Outside diff comments:
In `@tests/helpers/tooling_contracts/workflows.py`:
- Around line 457-471: Shorten the private helper docstrings to single-line
summaries: replace the structured docstring for _extract_apt_install_packages in
tests/helpers/tooling_contracts/workflows.py at lines 457-471 with one concise
description, and do the same for _assert_pinned_step_uses at lines 635-643.
Preserve each helper’s purpose while removing parameter, return-value, and
explanatory sections.
- Around line 513-517: Update the schedule assertion in the workflow contract
test to compare schedule directly with a single-entry list containing only
{"cron": _MUTATION_CRON}, replacing the any-based existential check. Preserve
the existing require_sequence lookup and failure message context while rejecting
extra schedules or fields.
- Around line 472-498: Update the setup-command parsing logic around the apt-get
marker to tokenize each complete logical shell command, then require the command
structure to be optional sudo followed by exact apt-get and install tokens
before extracting package names. Do not match embedded text such as echo
arguments, and add a negative test covering an echo containing “apt-get install”
without an actual installation command.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 01c4af09-cd83-46ef-892d-af84fe09899c
📒 Files selected for processing (2)
tests/helpers/tooling_contracts/workflows.pytests/test_helpers.py
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
leynos/whitaker(auto-detected)
Rework `_extract_apt_install_packages` so it recognises a real install
command rather than any line containing the substring "apt-get install".
Each logical line is tokenised with shlex, split on shell control operators
(`&&`, `||`, `;`, `|`, `&`), and a command counts only when its tokens are
an optional `sudo` followed by exactly `apt-get install`. Embedded text such
as an `echo "... apt-get install ..."` argument is now ignored. Add a
negative test covering that case.
Also address adjacent review points:
- Assert the mutation-testing `on.schedule` equals exactly
`[{"cron": _MUTATION_CRON}]`, rejecting extra schedule entries or fields,
instead of an existential any() check.
- Reduce the `_extract_apt_install_packages` and `_assert_pinned_step_uses`
docstrings to single-line summaries, matching the sibling helpers.
- Annotate the module-level Hypothesis strategy aliases with explicit
`SearchStrategy` element types so they stay statically checked.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The mutation-testing schedule assertion already requires
`schedule == [{"cron": _MUTATION_CRON}]`, but nothing proved the contract
actually rejects a non-conforming schedule, leaving the invariant asserted
only against the canonical rendered workflow.
Add two focused unit tests that drive `_assert_mutation_workflow_contracts`
with hand-built workflows and confirm it raises: one with a second schedule
entry beyond the sanctioned cron, and one with an extra key smuggled into
the single schedule entry. A small fixture builder populates just the
fields inspected before the schedule check so the assertion is exercised in
isolation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Adds
template/.github/workflows/mutation-testing.ymlso newly generated Rust repositories get scheduled mutation testing by default, matching the pattern already rolled out across the estate (for exampleleynos/mapsplice).The workflow is a thin caller of the shared reusable workflow
leynos/shared-actions/.github/workflows/mutation-cargo.yml. Caller guide: https://github.com/leynos/shared-actions/blob/main/docs/mutation-cargo-workflow.md.Details:
workflow_dispatch. The default cron is15 9 * * *; the estate already occupies the 03:05–09:05 UTC slots, and an inline comment tells maintainers of generated repositories to stagger their slot to avoid concurrent runs across the estate.permissions: {}; themutationjob opts in tocontents: readandid-token: write(OIDC workflow-source resolution).mutation-testing-${{ github.ref }}withcancel-in-progress: false, so dispatches queue behind scheduled runs rather than racing or cancelling.extra-args: "--all-features"mirrors the template CI test baseline (make testruns with--all-targets --all-features). Workspace-related inputs are omitted because the generated project is a single root crate.ci.ymlandact-validation.yml, as it needs no template variables; this also sidesteps the${{ }}Jinja/Actions syntax collision.docs/repository-layout.mdis updated to list the new workflow.mutation-testing.ymland assert its contract: root permissions grant no scopes, the mutation job calls the sharedmutation-cargoreusable workflow, the job permissions stay scoped tocontents: readandid-token: write,extra-argsmirrors the CI--all-featuresbaseline, and thesetup-commandsinstallclang,lld, andmold. The pinned reusable-workflow SHA is deliberately not asserted, as Dependabot owns and bumps that reference.Validation
copier copy --defaultsrenders cleanly and the workflow is copied verbatim.actionlintpasses on the rendered file.make test: 50 passed, 1 skipped (includes the new mutation-workflow contract assertions).References