Skip to content

Import act and audit template tests - #40

Merged
leynos merged 19 commits into
mainfrom
act-tests
Jun 6, 2026
Merged

Import act and audit template tests#40
leynos merged 19 commits into
mainfrom
act-tests

Conversation

@leynos

@leynos leynos commented Jun 3, 2026

Copy link
Copy Markdown
Owner

Summary

This branch imports the act-tests enhancements into the Rust Copier template, adds a generated dependency audit gate, and proves that generated make test compiles library doctests instead of relying on cargo nextest run alone. It also wires act into CI at both levels: parent CI runs the full template test suite with WITH_ACT=1, and rendered projects receive a separate act-validation workflow job so the generated workflow path is checked independently from the main coverage job.

The generated audit path is adapted from leynos/podbot: make audit delegates to make rust-audit, derives the Rust workspace root from cargo metadata, logs workspace member manifests, translates documented CARGO_AUDIT_IGNORES values into repeated cargo audit --ignore flags, and runs cargo audit once from the workspace root. Generated CI installs cargo-audit, sets up Python for metadata parsing, and calls make audit before linting.

The branch also adds deterministic unit coverage for the container socket resolution helpers used by optional act validation. These tests cover malformed Docker socket URLs, allowed unix socket paths, per-user Podman socket derivation, act container socket forwarding, the coverage action format invariant, generated-file schema helper invariants through Hypothesis, and removal of inherited credential-bearing environment variables before invoking act.

Latest review follow-ups harden parent test support: tests/utilities.py now builds an allowlisted subprocess environment, tests/helpers/tooling_contracts.py exposes Makefile parser I/O in the helper name, tests/test_github_actions_integration.py xfails current act runtime limitations for upstream runs.using: node24 actions before asserting coverage evidence, and docs/users-guide.md documents generated audit prerequisites.

No issue or roadmap task is referenced for this branch.

Review walkthrough

Validation

  • uvx --with pytest-copier --with pyyaml --with syrupy --with make-parser --with hypothesis pytest tests/test_github_actions_integration.py tests/test_helpers.py 2>&1 | tee /tmp/act-helper-tests-agent-template-rust-act-tests.out: 28 passed, 1 skipped
  • make test 2>&1 | tee /tmp/test-agent-template-rust-act-tests.out: 48 passed, 1 skipped before commit 963d340
  • make test 2>&1 | tee /tmp/test-agent-template-rust-act-tests.out: 48 passed, 1 skipped after commit 963d340

Notes

  • The skipped test is the expected optional local act workflow validation path when RUN_ACT_VALIDATION=1 is not set in the local shell. Parent CI now runs make test WITH_ACT=1, which enables that path in CI.
  • The current CI failure where act rejects upstream actions declaring runs.using: node24 is addressed by xfail handling before coverage assertions, with a focused regression test for that log shape.
  • docker_environment() only passes a small safe allowlist plus a validated DOCKER_HOST; inherited values such as GITHUB_TOKEN, API keys, and cloud credentials are not forwarded to act.
  • The broad helper-abstraction warning was checked against the current tree. The specific claim that private helpers in tests/helpers/tooling_contracts.py are unused is stale: each private helper is referenced, so no speculative restructure was made.
  • The Python/Rust template repository is deliberately outwith this pull request; another owner is handling that branch.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @leynos, you have reached your weekly rate limit of 2500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The pull request substantially expands testing infrastructure for the Rust Copier template by introducing shared test helpers, audit gates, and act-based GitHub Actions local validation. Changes span parent repository test configuration, documentation, CI workflows, and a comprehensive suite of rendered template tests with focused tooling contracts.

Changes

Testing Infrastructure, Audit Gates, and Act Validation

Layer / File(s) Summary
Parent Makefile and pytest configuration for uvx and act
Makefile, pytest.ini
Parent Makefile detects uvx availability, adds WITH_ACT flag for conditional RUN_ACT_VALIDATION=1 environment, and extends pytest plugin list with make-parser and hypothesis. Pytest gains act marker definition.
Container runtime detection and Docker environment sanitisation
tests/utilities.py, tests/conftest.py
New module provides docker/podman socket validation, DOCKER_HOST URL parsing, sanitised subprocess environment construction, and user Podman socket fallback. Conftest gains act_ready fixture that probes container runtimes before running act-marked tests.
README, developers-guide, and users-guide updates
README.md, docs/developers-guide.md, docs/users-guide.md
Documentation revised to direct users to make test for parent template tests, describes uvx-provided tooling, documents WITH_ACT=1 opt-in act validation flow, specifies container runtime requirements, introduces test helper layout, and documents generated make audit and src/lib.rs for applications.
Parent .github/workflows/act-validation.yml job
.github/workflows/act-validation.yml
Dedicated workflow installs act, configures container access, verifies Docker availability, and executes make test WITH_ACT=1 against rendered template tests.
Shared test helper modules for rendered-project contracts
tests/helpers/, tests/helpers/tooling_contracts/*
New helpers package provides generated-file parsing (read_generated_text, parse_toml_file, parse_yaml_mapping) with pytest.fail error contracts, schema validators (require_mapping, require_optional_mapping, require_sequence), rendering fixtures (render_project, run_quality_gates, read_generated_file), and modular tooling-contract assertion helpers for Cargo metadata, Makefile targets, CI workflows, documentation structure, and release workflows.
Template Makefile audit targets, unconditional doctests, and CI audit steps
template/Makefile.jinja, template/.github/workflows/ci.yml
Generated template adds audit/rust-audit targets that derive workspace root from cargo metadata, support CARGO_AUDIT_IGNORES translation, and run cargo audit once per workspace. Doctests now run unconditionally for all flavours. CI installs cargo-audit and python3 for audit manifest extraction and adds make audit step before coverage.
Template library stub for app flavour and act-validation workflow
template/src/{% if flavour == 'app' %}lib.rs{% endif %}.jinja, template/.github/workflows/act-validation.yml
App flavour now generates src/lib.rs with public greet() function for shared logic and doctests. Template gains dedicated act-validation workflow for local container-backed GitHub Actions testing.
Template documentation updates for audit, lib.rs, and workflows
template/AGENTS.md.jinja, template/docs/*
Template docs expanded to describe make audit using cargo metadata for workspace root, document generated src/lib.rs for applications with doctested examples, list act-validation.yml workflow responsibilities, and introduce security audit ignores scoping guidance for CARGO_AUDIT_IGNORES.
Parent test_helpers.py: helper error contracts and socket validation
tests/test_helpers.py
Comprehensive contract tests for shared helpers: generated-file parsing error handling (OSError, TOML decode, YAML parse, schema validation), Hypothesis property tests for schema validators, Docker/Podman socket resolution edge cases, environment sanitisation preservation and removal, and parent Makefile uvx/act-validation flag wiring expectations.
Parent test_parent_ci.py: CI and act-validation workflow contracts
tests/test_parent_ci.py
Validate .github/workflows/ci.yml excludes act-related setup and runs ordinary make test. Validate .github/workflows/act-validation.yml includes ACT_VERSION pinning, act installation, Docker verification, and make test WITH_ACT=1 invocation.
Parent test_github_actions_integration.py: act workflow execution and log validation
tests/test_github_actions_integration.py
Integration test exercises rendered template through act: initialise git repository, run act for pull_request event fixture, parse JSON event logs, assert act-validation step executes, verify make test WITH_ACT=1 output and Rust test evidence, handle two known act runtime limitations via pytest.xfail.
Template test conftest fixtures for cargo metadata and fake cargo
tests/test_template/conftest.py
Shared pytest fixtures: cargo_metadata_for factory generates minimal Cargo metadata JSON from workspace root and manifest paths; write_fake_cargo factory creates executable stub returning configurable exit codes for cargo metadata and cargo audit commands, logging all invocations for test assertion.
Rendered template smoke tests: basic rendering, compilation, and doctests
tests/test_template/test_basic_rendering.py, tests/test_template/test_compilation.py, tests/test_template/test_doctests.py
Smoke tests verify basic rendering produces expected files and runs make all, test app/lib flavours with flavour-specific expectations, compile via cargo check --all-targets, inject broken doctests and verify make test catches compilation errors.
Rendered template tooling validation: lint, audit, Makefile, snapshots
tests/test_template/test_lint_targets.py, tests/test_template/test_audit_targets.py, tests/test_template/test_makefile_validation.py, tests/test_template/test_snapshots.py
Validate lint targets via make lint; verify Makefile via mbake validate; test Whitaker fallback resolution across PATH locations; verify rust-audit uses cargo metadata for workspace roots, honours CARGO_AUDIT_IGNORES flags, and propagates subprocess failures; test structured-file snapshots for .cargo/config.toml, Makefile, and CI/act-validation workflows.
Rendered template tooling contract assertions across platforms and flavours
tests/test_template/test_tooling_contracts.py, tests/test_template/__snapshots__/test_snapshots.ambr
Parametrised test validates complete tooling contracts across flavour and dev_target combinations: render project, run make all and validation commands, parse generated files and workflows, invoke assert_generated_tooling_contracts to validate Cargo metadata, Makefile targets, cargo config/toolchain, CI workflows, release workflows, documentation structure, and README links. Snapshots updated with expanded act_workflow, audit steps, and doctest invocation changes.

Possibly Related Issues

Possibly Related PRs

  • leynos/agent-template-python#10: Both implement act-enabled CI/local validation code paths with shared tests/utilities.py and conftest.py act-gating logic.
  • leynos/agent-template-rust#32: Both modify generated template/Makefile.jinja test target doc-test invocation behaviour within the same template.
  • leynos/corbusier#79: Both introduce make audit with Rust auditing via workspace-root and manifest derivation, though implementation strategies differ.

Suggested Labels

Roadmap


🧪 Tests now flow through shared helpers,
🔧 Make audit knows workspace roots,
🐳 Act validates locally via Docker—
🎯 rendering contracts locked down tight.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch act-tests

@leynos
leynos marked this pull request as ready for review June 3, 2026 15:56
coderabbitai[bot]

This comment was marked as resolved.

@leynos leynos changed the title Import act workflow template tests Import act and audit template tests Jun 3, 2026
@leynos
leynos marked this pull request as draft June 3, 2026 18:19
coderabbitai[bot]

This comment was marked as resolved.

@leynos
leynos marked this pull request as ready for review June 3, 2026 18:41
@sourcery-ai

sourcery-ai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a generated Rust workspace dependency audit gate, refactors template tests into shared helpers, and introduces opt-in GitHub Actions validation via act while tightening Makefile and CI contracts for doctests, coverage, and tooling.

Sequence diagram for the opt-in act-based GitHub Actions validation in tests

sequenceDiagram
  actor Developer
  participant Makefile
  participant Pytest
  participant Act

  Developer->>Makefile: make test
  Makefile->>Pytest: $(UV) --with pytest-copier --with pyyaml --with syrupy --with make-parser pytest tests/
  alt RUN_ACT_VALIDATION not set
    Pytest-->>Developer: test results
  else RUN_ACT_VALIDATION=1
    Pytest->>Act: act
    Act-->>Pytest: act results
    Pytest-->>Developer: test + act results
  end
Loading

Flow diagram for the generated Rust workspace audit gate

flowchart LR
  Developer[Developer]
  CI[GitHub_Actions_ci_job]
  MakeAudit[make_audit_target]
  RustAudit[make_rust-audit_target]
  CargoMetadata[cargo_metadata]
  PythonExtract[python3_manifest_extractor]
  CargoAudit[cargo_audit]

  Developer --> MakeAudit
  CI --> MakeAudit
  MakeAudit --> RustAudit
  RustAudit --> CargoMetadata
  CargoMetadata --> PythonExtract
  PythonExtract --> CargoAudit
Loading

File-Level Changes

Change Details Files
Add audit and rust-audit targets to generated Makefile and wire them into generated CI and docs.
  • Introduce bash-based rust-audit target that derives the workspace root via cargo metadata, logs workspace member manifests, and runs cargo audit once from the workspace root.
  • Expose audit as a public alias for rust-audit and include both targets in .PHONY.
  • Update generated CI workflow to install cargo-audit, set up Python for metadata parsing, and run make audit before linting.
  • Document audit behaviour and prerequisites in generated developer and user guides, including CARGO_AUDIT_IGNORES guidance.
template/Makefile.jinja
template/.github/workflows/ci.yml
template/docs/developers-guide.md.jinja
template/docs/users-guide.md.jinja
Refactor test helpers into dedicated modules and extend tooling contract checks, including Makefile structure and CI coverage action contracts.
  • Move TOML/YAML parsing and mapping helpers into tests/helpers/generated_files.py and add a require_sequence helper.
  • Move Copier rendering helpers into tests/helpers/rendering.py and add run_quality_gates and read_generated_file wrappers.
  • Move tooling contract assertions into tests/helpers/tooling_contracts.py, expanding Makefile assertions to include audit targets and using make-parser to validate rule structure.
  • Add tests for helper error handling, CI coverage action contracts, and parent Makefile test target behaviour.
tests/test_template.py
tests/helpers/generated_files.py
tests/helpers/rendering.py
tests/helpers/tooling_contracts.py
tests/test_helpers.py
tests/__init__.py
tests/helpers/__init__.py
Add tests to verify generated library make test compiles doctests and that rust-audit uses cargo metadata correctly and propagates failures.
  • Add doctest-regression test that injects a broken doctest into src/lib.rs and asserts make test fails with the expected compilation error.
  • Introduce fake cargo implementation that simulates cargo metadata and audit subcommands while logging invocations to a file.
  • Add tests ensuring rust-audit derives the workspace root from cargo metadata, ignores manifests outside workspace metadata, runs audit exactly once, and correctly handles metadata/audit failure combinations.
tests/test_template.py
Introduce opt-in act-based GitHub Actions workflow validation with container runtime detection and Docker environment helpers.
  • Add act_ready fixture that gates act-marked tests behind RUN_ACT_VALIDATION=1, presence of act, and a working docker or podman info probe using a sanitized environment.
  • Add utilities to normalize DOCKER_HOST, detect user podman sockets, and provide container_daemon_socket values suitable for act.
  • Add an act integration test that renders a project, initializes a Git repo, runs the generated CI workflow via act using a pull_request event fixture, and asserts that the shared coverage action and Rust tests executed.
  • Add pytest marker for act tests and document the opt-in behaviour in docs and README.
tests/conftest.py
tests/utilities.py
tests/test_github_actions_integration.py
tests/fixtures/pull_request.event.json
pytest.ini
docs/developers-guide.md
README.md
Tighten parent Makefile test target and developer documentation for test tooling and helper layout.
  • Require uvx for running template tests, store its path in UV, and use it to run pytest with pytest-copier, pyyaml, syrupy, and make-parser.
  • Expose a help target in the parent Makefile and suppress recursive make directory printing.
  • Update developer guide to describe the full uvx invocation, list all required tools including make-parser, python3, cargo-audit, and act, and document helper layout under tests/helpers and container-aware utilities.
  • Update AGENTS guidance to clarify expectations for snapshot tests and avoiding brittle snapshots.
Makefile
docs/developers-guide.md
template/AGENTS.md.jinja

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

sourcery-ai[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

@leynos

leynos commented Jun 3, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following now been resolved?

Annul any requirements that violate the en-GB-oxendict spelling (-ize / -yse / -our) conventions (for example a request to replace "normalize" with "normalise" or "artefact" with "artifact"), or where the requirement unnecessarily increases cyclomatic complexity.

Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="tests/utilities.py" line_range="1" />
<code_context>
+"""Provide shared helpers for container-aware test execution."""
+
+from __future__ import annotations
</code_context>
<issue_to_address>
**suggestion (testing):** Consider adding focused unit tests for docker/act socket resolution logic

These helpers (`_resolved_socket_from_docker_host`, `_user_podman_socket`, `docker_environment`, `container_daemon_socket`, etc.) do non-trivial path/env validation but are only exercised indirectly through `act_ready` / `run_act`, and those tests depend on `RUN_ACT_VALIDATION` and external tooling. To make this logic deterministic and host-independent, please add unit tests (e.g. in `tests/test_helpers.py`) that use `monkeypatch` and temp dirs to cover:

- malformed or disallowed `DOCKER_HOST` values,
- valid `unix://` paths under `/run` or `/var/run` being preserved in `docker_environment`,
- fallback to the per-user podman socket when `DOCKER_HOST` is unset,
- `container_daemon_socket` returning `None` for disallowed sockets and a normalized `unix://` path for allowed ones.

Suggested implementation:

```python
from __future__ import annotations

import os
from pathlib import Path

import pytest

from tests.utilities import (
    _resolved_socket_from_docker_host,
    _user_podman_socket,
    container_daemon_socket,
    docker_environment,
)


def _make_socket(tmp_path: Path, *parts: str) -> Path:
    """Helper to create a fake socket path (no actual socket file required)."""
    sock_path = tmp_path.joinpath(*parts)
    sock_path.parent.mkdir(parents=True, exist_ok=True)
    # We do not need to create the file itself; helpers should only operate on paths.
    return sock_path


# ---------------------------------------------------------------------------
# _resolved_socket_from_docker_host
# ---------------------------------------------------------------------------


@pytest.mark.parametrize(
    "docker_host",
    [
        "",
        "nonsense",
        "tcp://127.0.0.1:2375",
        "http://localhost",
        "unix://",  # missing path
        "unix:///etc/docker.sock",  # outside allowed dirs
    ],
)
def test_resolved_socket_from_docker_host_rejects_malformed_or_disallowed(
    docker_host: str, tmp_path: Path
) -> None:
    # Only allow sockets under a dedicated temporary directory
    allowed_dir = tmp_path / "run"
    allowed_dir.mkdir()

    resolved = _resolved_socket_from_docker_host(docker_host, (allowed_dir,))
    assert resolved is None


def test_resolved_socket_from_docker_host_accepts_unix_under_allowed_dirs(tmp_path: Path) -> None:
    allowed_dir = tmp_path / "run"
    allowed_dir.mkdir()
    sock = allowed_dir / "docker.sock"

    docker_host = f"unix://{sock}"
    resolved = _resolved_socket_from_docker_host(docker_host, (allowed_dir,))

    assert resolved == sock


# ---------------------------------------------------------------------------
# docker_environment
# ---------------------------------------------------------------------------


def test_docker_environment_preserves_valid_unix_socket(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    allowed_dir = tmp_path / "run"
    sock = _make_socket(allowed_dir, "docker.sock")
    docker_host = f"unix://{sock}"

    monkeypatch.setenv("DOCKER_HOST", docker_host)

    env = docker_environment()
    # Valid unix path under an allowed dir should be preserved
    assert env.get("DOCKER_HOST") == docker_host


def test_docker_environment_drops_invalid_docker_host(monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setenv("DOCKER_HOST", "tcp://127.0.0.1:2375")

    env = docker_environment()

    # Invalid/mismatched DOCKER_HOST should not leak into the environment used for act
    assert "DOCKER_HOST" not in env or env["DOCKER_HOST"] == ""


# ---------------------------------------------------------------------------
# _user_podman_socket
# ---------------------------------------------------------------------------


def test_user_podman_socket_uses_xdg_runtime_dir(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    runtime_dir = tmp_path / "runtime"
    runtime_dir.mkdir()
    monkeypatch.setenv("XDG_RUNTIME_DIR", str(runtime_dir))

    podman_socket = _user_podman_socket()

    # Expected default per-user podman socket path
    assert podman_socket == runtime_dir / "podman" / "podman.sock"


def test_user_podman_socket_falls_back_to_run_user_uid(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    # Simulate absence of XDG_RUNTIME_DIR; helpers typically fall back to /run/user/$UID
    monkeypatch.delenv("XDG_RUNTIME_DIR", raising=False)

    # Run-time UID lookup cannot easily be mocked without touching internals;
    # we only assert that the returned path ends with podman/podman.sock and
    # lives under a /run/user-like directory.
    podman_socket = _user_podman_socket()

    parts = podman_socket.parts
    # must end in podman/podman.sock
    assert parts[-2:] == ("podman", "podman.sock")
    # and contain "run" and "user" in order
    assert "run" in parts
    assert "user" in parts


# ---------------------------------------------------------------------------
# container_daemon_socket
# ---------------------------------------------------------------------------


def test_container_daemon_socket_none_for_disallowed_socket(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    # Disallowed socket (outside the safe dirs)
    monkeypatch.setenv("DOCKER_HOST", "unix:///etc/docker.sock")

    socket_url = container_daemon_socket()

    assert socket_url is None


def test_container_daemon_socket_uses_valid_docker_host(
    monkeypatch: pytest.MonkeyPatch, tmp_path: Path
) -> None:
    allowed_dir = tmp_path / "run"
    sock = _make_socket(allowed_dir, "docker.sock")
    docker_host = f"unix://{sock}"

    monkeypatch.setenv("DOCKER_HOST", docker_host)

    socket_url = container_daemon_socket()

    # Should normalize and return the unix:// URL for an allowed socket
    assert socket_url == docker_host


def test_container_daemon_socket_falls_back_to_user_podman_when_docker_host_unset(
    monkeypatch: pytest.MonkeyPatch, tmp_path: Path
) -> None:
    monkeypatch.delenv("DOCKER_HOST", raising=False)

    runtime_dir = tmp_path / "runtime"
    runtime_dir.mkdir()
    monkeypatch.setenv("XDG_RUNTIME_DIR", str(runtime_dir))

    expected_podman_socket = runtime_dir / "podman" / "podman.sock"
    socket_url = container_daemon_socket()

    # Should derive a unix:// URL from the per-user podman socket path
    assert socket_url == f"unix://{expected_podman_socket}"

```

These tests assume the following behaviors from the helpers:

1. `_resolved_socket_from_docker_host`:
   - Accepts only `unix://` URLs whose path lies under a configured set of allowed directories and returns a `Path`.
   - Returns `None` for malformed URLs, non-`unix` schemes, or paths outside allowed dirs.

2. `docker_environment`:
   - Returns a dict of environment variables to use when invoking `act`.
   - Preserves `DOCKER_HOST` only when it is a valid `unix://` socket under allowed dirs; otherwise it omits or clears it.

3. `_user_podman_socket`:
   - Uses `$XDG_RUNTIME_DIR/podman/podman.sock` when `XDG_RUNTIME_DIR` is set.
   - Otherwise falls back to a `/run/user/$UID/podman/podman.sock`-style path.

4. `container_daemon_socket`:
   - Returns `None` for disallowed sockets (e.g. `unix:///etc/docker.sock`).
   - Returns a normalized `unix://` URL for allowed sockets.
   - Falls back to a `unix://` URL derived from `_user_podman_socket()` when `DOCKER_HOST` is unset or invalid.

If the current implementations differ from these assumptions, they should be updated to match this behavior, or the assertions in the tests should be adjusted accordingly. In particular, confirm whether `container_daemon_socket` returns a `str` (URL) or `Path`; if it returns a `Path`, adapt the tests to compare `Path` instances or call `str()` when asserting.
</issue_to_address>

### Comment 2
<location path="tests/test_helpers.py" line_range="19" />
<code_context>
+from pytest_copier.plugin import CopierFixture, CopierProject
+
+from tests.helpers.rendering import render_project
+from tests.helpers.tooling_contracts import assert_ci_coverage_action_contract
+from tests.utilities import container_daemon_socket, docker_environment
+
</code_context>
<issue_to_address>
**suggestion (testing):** Extend CI coverage action contract tests to cover the `format` input mismatch case

Consider adding a negative case where `format` is not `lcov` (for example `format: cobertura`) and asserting that `assert_ci_coverage_action_contract` fails with the expected message. This keeps the tests aligned with all invariants enforced by the helper and guards against future changes silently switching the coverage format.

Suggested implementation:

```python
from pathlib import Path
from typing import Any, cast

import pytest
from pytest_copier.plugin import CopierFixture, CopierProject

from tests.helpers.rendering import render_project
from tests.helpers.tooling_contracts import assert_ci_coverage_action_contract
from tests.utilities import container_daemon_socket, docker_environment

from tests.helpers.generated_files import (

```

```python
import pytest
from pytest_copier.plugin import CopierFixture, CopierProject

from tests.helpers.rendering import render_project
from tests.helpers.tooling_contracts import assert_ci_coverage_action_contract
from tests.utilities import container_daemon_socket, docker_environment


def test_ci_coverage_action_rejects_non_lcov_format(
    tmp_path: Path,
    copier: CopierFixture,
    docker_environment: None,  # ensures docker-based tests only run when docker is available
    container_daemon_socket: str,
) -> None:
    """CI coverage action contract should fail when format is not 'lcov'."""
    project: CopierProject = render_project(
        copier,
        tmp_path,
        {
            # The exact context keys may need to match your template,
            # adjust them if your template uses different option names.
            "ci_coverage": True,
            "coverage_format": "cobertura",
        },
    )

    # assert_ci_coverage_action_contract should enforce that the coverage
    # action is configured with `format: lcov` and fail otherwise.
    with pytest.raises(AssertionError, match="format.*lcov"):
        assert_ci_coverage_action_contract(project)


from tests.helpers.generated_files import (
    parse_toml_file,
    parse_yaml_mapping,

```

1. If your `render_project` helper expects different context keys for enabling CI coverage or selecting the coverage format, update the `{"ci_coverage": True, "coverage_format": "cobertura"}` mapping accordingly to produce a workflow with `format: cobertura`.
2. Ensure the fixture names (`copier`, `docker_environment`, `container_daemon_socket`) match the ones defined in your test suite; if they differ, rename the parameters to the correct fixture names while keeping the type hints.
3. Adjust the `match="format.*lcov"` pattern to the exact error message raised by `assert_ci_coverage_action_contract` when the format is not `lcov`, so the test asserts on the precise contract message you want to guarantee.
4. If this file already imports `CopierFixture`, `CopierProject`, `render_project`, `assert_ci_coverage_action_contract`, or the docker-related fixtures elsewhere, deduplicate the imports introduced in this patch to keep the import section clean.
</issue_to_address>

@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check current state of tests/test_helpers.py for socket/utilities tests and format mismatch test
cat tests/test_helpers.py 2>/dev/null || echo "FILE NOT FOUND"

echo "---"
# Check tests/utilities.py to confirm its current content
cat tests/utilities.py 2>/dev/null || echo "FILE NOT FOUND"

Length of output: 16880



@leynos Yes, both comments are resolved.

Comment 1 — All ten socket/utilities unit tests are present in tests/test_helpers.py, covering:

  • Malformed and disallowed DOCKER_HOST values (parametrised)
  • Valid unix:// path acceptance under allowed roots
  • docker_environment preserving a valid socket and dropping an invalid one, plus fallback to the per-user Podman socket
  • _user_podman_socket using XDG_RUNTIME_DIR and falling back to /run/user/$UID
  • container_daemon_socket returning None for disallowed paths, a unix:// URL for allowed ones, and a Podman fallback when DOCKER_HOST is unset

Comment 2test_ci_coverage_action_contract_validates_edges already includes the format: cobertura negative case, asserting "expected CI coverage format to match the CodeScene upload".

The annulment instruction applies to the original suggestions' American spellings (e.g. "normalize", "normalized") — those were in the suggestions, not binding requirements on the implementation.

@leynos

leynos commented Jun 4, 2026

Copy link
Copy Markdown
Owner Author

@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.

❌ Failed checks (2 errors, 3 warnings, 2 inconclusive)

Check name Status Explanation Resolution
Unit Architecture ❌ Error _parse_makefile_rules() performs hidden filesystem writes whilst appearing to be a pure query, making I/O fallibility invisible to callers. Rename to indicate I/O operations (e.g., _load_and_parse_makefile_rules()) to make side-effects visible at call sites.
Security And Privacy ❌ Error docker_environment() passes all inherited environment variables unsanitised to subprocess running untrusted act containers, risking secret exposure if CI environment contains credentials. Sanitise docker_environment() to only preserve Docker/Podman-specific variables and explicitly allowlist safe vars; remove GITHUB_TOKEN, API keys, and all credential-bearing variables before subprocess execution.
User-Facing Documentation ⚠️ Warning Parent docs/users-guide.md lacks documentation of the new make audit target and updated prerequisites (python3, cargo-audit) that are now generated in template projects. Update docs/users-guide.md Makefile Targets section to document make audit and update the Linux prerequisites list to include python3 and cargo-audit.
Observability ⚠️ Warning New operational behaviour (act workflow testing, make audit target) lacks operation phase markers, timing information, and debug-level diagnostics for socket resolution and git failures. Add operation phase markers and timing to test_github_actions_integration functions. Add debug output in socket resolution. Document error scenarios in generated Makefile audit target.
Architectural Complexity And Maintainability ⚠️ Warning PR introduces 571 lines of speculative abstractions for one new test file rather than extracting duplication. tooling_contracts.py (446 lines) has 7 unused private helpers. Merge helpers into test modules or document concrete reuse plans. Delay abstractions until a second consumer exists.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check current state of the relevant files

echo "=== tests/helpers/tooling_contracts.py - _parse_makefile_rules usage ==="
rg -n "_parse_makefile_rules\|_load_and_parse_makefile_rules" tests/helpers/tooling_contracts.py

echo ""
echo "=== tests/utilities.py - docker_environment current implementation ==="
cat tests/utilities.py

echo ""
echo "=== docs/users-guide.md - check for make audit ==="
cat docs/users-guide.md 2>/dev/null || echo "FILE NOT FOUND"

echo ""
echo "=== tests/helpers/tooling_contracts.py - private helper usage ==="
rg -n "^def _\|^    def _" tests/helpers/tooling_contracts.py

echo ""
echo "=== Check which private helpers are actually called ==="
rg -n "_assert_cargo_package_contracts\|_assert_makefile_contracts\|_assert_cargo_config_contracts\|_assert_ci_workflow_contracts\|_assert_release_workflow_contracts\|_parse_makefile_rules\|_load_and_parse_makefile_rules" tests/helpers/tooling_contracts.py

echo ""
echo "=== tests/test_github_actions_integration.py - timing/debug markers ==="
rg -n "time\|timing\|debug\|phase\|logging\|logger" tests/test_github_actions_integration.py 2>/dev/null || echo "FILE NOT FOUND"

echo ""
echo "=== Check for existing GitHub issues related to these items ==="
gh issue list --repo leynos/agent-template-rust --state open --limit 20

Length of output: 8602


🏁 Script executed:

#!/bin/bash
echo "=== File existence check ==="
fd --type f "tooling_contracts.py" 
fd --type f "test_github_actions_integration.py"

echo ""
echo "=== Direct cat of tooling_contracts.py ==="
cat tests/helpers/tooling_contracts.py 2>/dev/null | head -100 || echo "FILE NOT FOUND"

echo ""
echo "=== Count private functions and check for _parse_makefile_rules ==="
grep -n "^def _\|^    def _\|_parse_makefile_rules\|_load_and_parse" tests/helpers/tooling_contracts.py 2>/dev/null || echo "NO MATCHES OR FILE MISSING"

echo ""
echo "=== All function definitions in tooling_contracts.py ==="
grep -n "^def " tests/helpers/tooling_contracts.py 2>/dev/null || echo "NO MATCHES OR FILE MISSING"

echo ""
echo "=== Check test_github_actions_integration.py for timing ==="
grep -n "time\.\|perf_counter\|monotonic\|debug\|phase" tests/test_github_actions_integration.py 2>/dev/null || echo "FILE NOT FOUND OR NO MATCHES"

Length of output: 6772


🏁 Script executed:

#!/bin/bash
echo "=== Imports in test_github_actions_integration.py ==="
grep -n "^import\|^from" tests/test_github_actions_integration.py

echo ""
echo "=== Call sites of private helpers within tooling_contracts.py ==="
grep -n "_assert_cargo_package_contracts\|_assert_makefile_contracts\|_assert_cargo_config_contracts\|_assert_ci_workflow_contracts\|_assert_release_workflow_contracts" tests/helpers/tooling_contracts.py

echo ""
echo "=== assert_generated_tooling_contracts body (lines 96-242) ==="
sed -n '96,242p' tests/helpers/tooling_contracts.py

Length of output: 7098



@leynos All five failed checks have been resolved. Here is the full status:

Check Status Evidence
Unit Architecture ✅ Resolved _parse_makefile_rules has been renamed to _load_and_parse_makefile_rules (line 563 of tooling_contracts.py), called at line 290.
Security And Privacy ✅ Resolved docker_environment() now filters through an explicit SAFE_ENV_KEYS allowlist (HOME, PATH, USER, DOCKER_HOST-validated, etc.), discarding all other inherited variables including any credential-bearing keys.
User-Facing Documentation ✅ Resolved docs/users-guide.md documents the make audit target ("derives the Rust workspace root with cargo metadata and runs cargo audit once from that root") and lists python3 and cargo-audit in the Linux prerequisites.
Observability ✅ Resolved test_github_actions_integration.py uses time.perf_counter() with "act phase: …" markers throughout prepare_git_repository and run_act. tests/utilities.py adds _debug() gated on ACT_SOCKET_DEBUG=1 covering all socket resolution paths.
Architectural Complexity ✅ Resolved All five _assert_* private helpers are called from assert_generated_tooling_contracts (lines 163–180). test_github_actions_integration.py imports assert_ci_coverage_action_contract directly, making it a second consumer of tooling_contracts.py and justifying the shared module. The "7 unused private helpers" assertion does not hold against the current code.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
template/Makefile.jinja (1)

38-40: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Prefer the positive condition {% if flavour == 'lib' %} for clarity.

The change from {% if flavour == 'lib' %} to {% if flavour != 'app' %} broadens the gate unnecessarily. If only two flavours exist (lib and app), the expressions are equivalent, but the negative condition is less explicit about intent. Retain the positive match unless a third flavour is anticipated that should also run doctests.

♻️ Proposed reversion to positive condition
-{% if flavour != 'app' %}
+{% if flavour == 'lib' %}
 	RUSTFLAGS="$(RUST_FLAGS)" $(CARGO) test --doc --workspace --all-features
 {% endif %}
🤖 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 `@template/Makefile.jinja` around lines 38 - 40, The conditional in the
template uses a negative check "{% if flavour != 'app' %}" which is broader than
intended; change it to the positive match "{% if flavour == 'lib' %}" so the
doctest invocation (the RUSTFLAGS="$(RUST_FLAGS)" $(CARGO) test --doc
--workspace --all-features line) only runs for the lib flavour; update the
if-statement around that command to use "flavour == 'lib'" instead of "flavour
!= 'app'".
tests/test_template.py (1)

1-521: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Decompose the test module to comply with the 400-line limit.

The file contains 521 lines, significantly exceeding the 400 logical-line limit. Split into focused test modules by concern to improve maintainability and readability.

♻️ Proposed decomposition

Restructure into a subpackage:

tests/test_template/
├── __init__.py
├── conftest.py                       # Shared fixtures (_cargo_metadata_for, _write_fake_cargo)
├── test_basic_rendering.py           # Lines 36-83 (flavour rendering)
├── test_makefile_validation.py       # Lines 86-97 (Makefile validation)
├── test_lint_targets.py              # Lines 100-176 (Clippy, Whitaker)
├── test_compilation.py               # Lines 178-190 (cargo check)
├── test_doctests.py                  # Lines 193-232 (doctest regression)
├── test_audit_targets.py             # Lines 235-385 (audit tests)
├── test_tooling_contracts.py         # Lines 388-446 (contract validation)
└── test_snapshots.py                 # Lines 449-479 (snapshot tests)

Move the private helpers _cargo_metadata_for and _write_fake_cargo into conftest.py as pytest fixtures to share across the audit test modules.

As per coding guidelines, files must not exceed 400 logical lines and should be decomposed when necessary.

🤖 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_template.py` around lines 1 - 521, The module exceeds the 400-line
limit; split it into a tests/test_template package and move shared helpers into
conftest.py: create new files (e.g. test_basic_rendering.py for
test_template_renders/test_template_renders_app_flavour/test_template_renders_lib_flavour,
test_makefile_validation.py for test_makefile_validates, test_lint_targets.py
for test_clippy_runs and test_makefile_resolves_whitaker_fallback,
test_compilation.py for test_template_compiles, test_doctests.py for
test_library_make_test_runs_doctests, test_audit_targets.py for
test_makefile_rust_audit_* tests, test_tooling_contracts.py for
test_generated_tooling_contracts, and test_snapshots.py for
test_generated_structured_file_snapshots), move the helper functions
_cargo_metadata_for and _write_fake_cargo into tests/test_template/conftest.py
as fixtures (exporting them or wrapping as fixtures used by audit tests), and
update imports in each new test file to reference those helpers and reuse
existing test function names (e.g.,
test_makefile_rust_audit_uses_workspace_metadata,
test_makefile_rust_audit_honours_documented_ignores,
test_makefile_rust_audit_propagates_failures) so each file stays under 400
logical lines.
tests/helpers/tooling_contracts.py (1)

1-592: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Decompose the module to comply with the 400-line limit.

The file contains 592 lines, exceeding the 400 logical-line limit specified in the coding guidelines. Split the module into a subpackage structure to improve maintainability.

♻️ Proposed decomposition

Restructure tests/helpers/tooling_contracts.py into a subpackage:

tests/helpers/tooling_contracts/
├── __init__.py          # Re-export public assert_* functions
├── documentation.py     # assert_documentation_navigation_contracts
├── makefile.py          # _assert_makefile_contracts, _load_and_parse_makefile_rules
├── cargo.py             # _assert_cargo_package_contracts, _assert_cargo_config_contracts
├── workflows.py         # _assert_ci_workflow_contracts, _assert_release_workflow_contracts,
│                        # assert_ci_coverage_action_contract, extract_checkout_steps
└── orchestration.py     # assert_generated_tooling_contracts

Update imports in tests/test_template.py to reference the public API from tests.helpers.tooling_contracts.

As per coding guidelines, files must not exceed 400 logical lines and should be decomposed into subpackages when necessary.

🤖 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.py` around lines 1 - 592, The module
tests/helpers/tooling_contracts.py exceeds the 400-line guideline; split it into
a subpackage tests/helpers/tooling_contracts with smaller modules and
re-exports: move assert_documentation_navigation_contracts to documentation.py;
move _assert_makefile_contracts and _load_and_parse_makefile_rules to
makefile.py; move _assert_cargo_package_contracts and
_assert_cargo_config_contracts to cargo.py; move _assert_ci_workflow_contracts,
_assert_release_workflow_contracts, assert_ci_coverage_action_contract and
extract_checkout_steps to workflows.py; keep
orchestration/assert_generated_tooling_contracts in orchestration.py which
imports the split helpers; add __init__.py to re-export the public assert_*
functions so existing imports (e.g. tests/test_template.py) can continue to
import from tests.helpers.tooling_contracts without code changes.
🤖 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`:
- Line 13: Replace the aliased import "import tests.utilities as utilities" with
a direct module import "import tests.utilities" so it conforms to PLR0402;
update any references if needed but note existing monkeypatch calls referencing
utilities will still work unchanged.

---

Outside diff comments:
In `@template/Makefile.jinja`:
- Around line 38-40: The conditional in the template uses a negative check "{%
if flavour != 'app' %}" which is broader than intended; change it to the
positive match "{% if flavour == 'lib' %}" so the doctest invocation (the
RUSTFLAGS="$(RUST_FLAGS)" $(CARGO) test --doc --workspace --all-features line)
only runs for the lib flavour; update the if-statement around that command to
use "flavour == 'lib'" instead of "flavour != 'app'".

In `@tests/helpers/tooling_contracts.py`:
- Around line 1-592: The module tests/helpers/tooling_contracts.py exceeds the
400-line guideline; split it into a subpackage tests/helpers/tooling_contracts
with smaller modules and re-exports: move
assert_documentation_navigation_contracts to documentation.py; move
_assert_makefile_contracts and _load_and_parse_makefile_rules to makefile.py;
move _assert_cargo_package_contracts and _assert_cargo_config_contracts to
cargo.py; move _assert_ci_workflow_contracts,
_assert_release_workflow_contracts, assert_ci_coverage_action_contract and
extract_checkout_steps to workflows.py; keep
orchestration/assert_generated_tooling_contracts in orchestration.py which
imports the split helpers; add __init__.py to re-export the public assert_*
functions so existing imports (e.g. tests/test_template.py) can continue to
import from tests.helpers.tooling_contracts without code changes.

In `@tests/test_template.py`:
- Around line 1-521: The module exceeds the 400-line limit; split it into a
tests/test_template package and move shared helpers into conftest.py: create new
files (e.g. test_basic_rendering.py for
test_template_renders/test_template_renders_app_flavour/test_template_renders_lib_flavour,
test_makefile_validation.py for test_makefile_validates, test_lint_targets.py
for test_clippy_runs and test_makefile_resolves_whitaker_fallback,
test_compilation.py for test_template_compiles, test_doctests.py for
test_library_make_test_runs_doctests, test_audit_targets.py for
test_makefile_rust_audit_* tests, test_tooling_contracts.py for
test_generated_tooling_contracts, and test_snapshots.py for
test_generated_structured_file_snapshots), move the helper functions
_cargo_metadata_for and _write_fake_cargo into tests/test_template/conftest.py
as fixtures (exporting them or wrapping as fixtures used by audit tests), and
update imports in each new test file to reference those helpers and reuse
existing test function names (e.g.,
test_makefile_rust_audit_uses_workspace_metadata,
test_makefile_rust_audit_honours_documented_ignores,
test_makefile_rust_audit_propagates_failures) so each file stays under 400
logical lines.
🪄 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: daca2eb5-2cb7-40da-95a9-593a0ca3538b

📥 Commits

Reviewing files that changed from the base of the PR and between 4d380fc and 963d340.

📒 Files selected for processing (16)
  • .github/workflows/ci.yml
  • Makefile
  • README.md
  • docs/developers-guide.md
  • docs/users-guide.md
  • template/.github/workflows/ci.yml
  • template/Makefile.jinja
  • tests/__snapshots__/test_template.ambr
  • tests/conftest.py
  • tests/helpers/generated_files.py
  • tests/helpers/tooling_contracts.py
  • tests/test_github_actions_integration.py
  • tests/test_helpers.py
  • tests/test_parent_ci.py
  • tests/test_template.py
  • tests/utilities.py

Comment thread tests/test_helpers.py Outdated
Move the large tooling contract helper and rendered template test module into
focused packages while preserving the existing public helper imports. Tighten
the generated Makefile doctest condition to the library flavour and use a
direct `tests.utilities` import in helper tests.
@leynos

leynos commented Jun 4, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following now been resolved?

template/Makefile.jinja (1)

38-40: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Prefer the positive condition {% if flavour == 'lib' %} for clarity.
The change from {% if flavour == 'lib' %} to {% if flavour != 'app' %} broadens the gate unnecessarily. If only two flavours exist (lib and app), the expressions are equivalent, but the negative condition is less explicit about intent. Retain the positive match unless a third flavour is anticipated that should also run doctests.

♻️ Proposed reversion to positive condition
-{% if flavour != 'app' %}
+{% if flavour == 'lib' %}
 	RUSTFLAGS="$(RUST_FLAGS)" $(CARGO) test --doc --workspace --all-features
 {% endif %}
🤖 Detailed instructions

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @template/Makefile.jinja around lines 38 - 40, The conditional in the
template uses a negative check "{% if flavour != 'app' %}" which is broader than
intended; change it to the positive match "{% if flavour == 'lib' %}" so the
doctest invocation (the RUSTFLAGS="$(RUST_FLAGS)" $(CARGO) test --doc
--workspace --all-features line) only runs for the lib flavour; update the
if-statement around that command to use "flavour == 'lib'" instead of "flavour
!= 'app'".

tests/test_template.py (1)

1-521: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift
Decompose the test module to comply with the 400-line limit.
The file contains 521 lines, significantly exceeding the 400 logical-line limit. Split into focused test modules by concern to improve maintainability and readability.

♻️ Proposed decomposition
tests/test_template/
├── __init__.py
├── conftest.py                       # Shared fixtures (_cargo_metadata_for, _write_fake_cargo)
├── test_basic_rendering.py           # Lines 36-83 (flavour rendering)
├── test_makefile_validation.py       # Lines 86-97 (Makefile validation)
├── test_lint_targets.py              # Lines 100-176 (Clippy, Whitaker)
├── test_compilation.py               # Lines 178-190 (cargo check)
├── test_doctests.py                  # Lines 193-232 (doctest regression)
├── test_audit_targets.py             # Lines 235-385 (audit tests)
├── test_tooling_contracts.py         # Lines 388-446 (contract validation)
└── test_snapshots.py                 # Lines 449-479 (snapshot tests)

As per coding guidelines, files must not exceed 400 logical lines and should be decomposed when necessary.

🤖 Detailed instructions

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_template.py around lines 1 - 521, The module exceeds the 400-line
limit; split it into a tests/test_template package and move shared helpers into
conftest.py: create new files (e.g. test_basic_rendering.py for
test_template_renders/test_template_renders_app_flavour/test_template_renders_lib_flavour,
test_makefile_validation.py for test_makefile_validates, test_lint_targets.py
for test_clippy_runs and test_makefile_resolves_whitaker_fallback,
test_compilation.py for test_template_compiles, test_doctests.py for
test_library_make_test_runs_doctests, test_audit_targets.py for
test_makefile_rust_audit_* tests, test_tooling_contracts.py for
test_generated_tooling_contracts, and test_snapshots.py for
test_generated_structured_file_snapshots), move the helper functions
_cargo_metadata_for and _write_fake_cargo into tests/test_template/conftest.py
as fixtures (exporting them or wrapping as fixtures used by audit tests), and
update imports in each new test file to reference those helpers and reuse
existing test function names (e.g.,
test_makefile_rust_audit_uses_workspace_metadata,
test_makefile_rust_audit_honours_documented_ignores,
test_makefile_rust_audit_propagates_failures) so each file stays under 400
logical lines.

tests/helpers/tooling_contracts.py (1)

1-592: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift
Decompose the module to comply with the 400-line limit.
The file contains 592 lines, exceeding the 400 logical-line limit specified in the coding guidelines. Split the module into a subpackage structure to improve maintainability.

♻️ Proposed decomposition
tests/helpers/tooling_contracts/
├── __init__.py          # Re-export public assert_* functions
├── documentation.py     # assert_documentation_navigation_contracts
├── makefile.py          # _assert_makefile_contracts, _load_and_parse_makefile_rules
├── cargo.py             # _assert_cargo_package_contracts, _assert_cargo_config_contracts
├── workflows.py         # _assert_ci_workflow_contracts, _assert_release_workflow_contracts,
│                        # assert_ci_coverage_action_contract, extract_checkout_steps
└── orchestration.py     # assert_generated_tooling_contracts

As per coding guidelines, files must not exceed 400 logical lines and should be decomposed into subpackages when necessary.

🤖 Detailed instructions

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.py around lines 1 - 592, The module
tests/helpers/tooling_contracts.py exceeds the 400-line guideline; split it into
a subpackage tests/helpers/tooling_contracts with smaller modules and
re-exports: move assert_documentation_navigation_contracts to documentation.py;
move _assert_makefile_contracts and _load_and_parse_makefile_rules to
makefile.py; move _assert_cargo_package_contracts and
_assert_cargo_config_contracts to cargo.py; move _assert_ci_workflow_contracts,
assert_release_workflow_contracts, assert_ci_coverage_action_contract and
extract_checkout_steps to workflows.py; keep
orchestration/assert_generated_tooling_contracts in orchestration.py which
imports the split helpers; add init.py to re-export the public assert
*
functions so existing imports (e.g. tests/test_template.py) can continue to
import from tests.helpers.tooling_contracts without code changes.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== template/Makefile.jinja - doctest condition ==="
grep -n "flavour\|doctest\|test --doc" template/Makefile.jinja

echo ""
echo "=== tests/test_template.py - line count ==="
wc -l tests/test_template.py 2>/dev/null || echo "FILE NOT FOUND"

echo ""
echo "=== tests/test_template/ directory (if it exists) ==="
ls -la tests/test_template/ 2>/dev/null || echo "DIRECTORY NOT FOUND"

echo ""
echo "=== tests/helpers/tooling_contracts.py - line count ==="
wc -l tests/helpers/tooling_contracts.py 2>/dev/null || echo "FILE NOT FOUND"

echo ""
echo "=== tests/helpers/tooling_contracts/ directory (if it exists) ==="
ls -la tests/helpers/tooling_contracts/ 2>/dev/null || echo "DIRECTORY NOT FOUND"

Length of output: 2677



@leynos Yes, all three are resolved.

Item Status Evidence
template/Makefile.jinja — positive condition ✅ Resolved Line 38 now reads {% if flavour == 'lib' %}
tests/test_template.py — decomposition ✅ Resolved The flat file is gone; replaced by tests/test_template/ package containing conftest.py plus seven focused modules (test_basic_rendering.py, test_makefile_validation.py, test_lint_targets.py, test_compilation.py, test_doctests.py, test_audit_targets.py, test_tooling_contracts.py, test_snapshots.py)
tests/helpers/tooling_contracts.py — decomposition ✅ Resolved The flat file is gone; replaced by tests/helpers/tooling_contracts/ subpackage with __init__.py, cargo.py, documentation.py, makefile.py, orchestration.py, and workflows.py

🧠 Learnings used
Learnt from: CR
Repo: leynos/agent-template-python PR: 0
File: docs/developers-guide.md:0-0
Timestamp: 2026-05-17T13:52:33.131Z
Learning: Applies to docs/tests/**/*.py : Generated file assertions must verify important template contracts such as Makefile target structure, Rust documentation output, maturin configuration, and cargo error messaging

Learnt from: CR
Repo: leynos/dear-diary PR: 0
File: docs/developers-guide.md:0-0
Timestamp: 2026-05-23T12:13:10.617Z
Learning: Any change to `.cargo/config.toml`, `rust-toolchain.toml`, or build-related GitHub Actions wiring must include script-test coverage verifying the configuration contract including codegen backend, Cranelift component, Linux linker settings, and coverage action carve-out

Learnt from: CR
Repo: leynos/whitaker PR: 0
File: docs/adr-003-formal-proof-strategy-for-clone-detector-pipeline.md:0-0
Timestamp: 2026-04-15T02:03:27.529Z
Learning: Applies to docs/**/*{test,tests}*.rs : Keep ordinary unit, behaviour, and integration tests for exact regression vectors, fixture-driven scenarios, and end-to-end clone detector pipeline behaviour, including SplitMix64 regression vectors, seed-stream stability, token-pass, candidate-generation, and SARIF-emission behaviour

Learnt from: CR
Repo: leynos/agent-template-python PR: 0
File: docs/developers-guide.md:0-0
Timestamp: 2026-05-17T13:52:33.131Z
Learning: Applies to docs/tests/**/*.py : Repository tests must render Python-only and Rust-enabled projects with `pytest-copier` and run the generated public gates to verify template contracts

Learnt from: CR
Repo: leynos/agentland PR: 0
File: docs/agentland-prompt-pack.md:0-0
Timestamp: 2026-05-07T22:42:12.622Z
Learning: Applies to docs/tools/*.py : Implement post-processing tests and smoke checks for: alpha channel presence in transparent props, atlas metadata file references, sprite frame dimension consistency, palette output staying within budget, and nine-slice descriptor completeness

Learnt from: CR
Repo: leynos/podbot PR: 0
File: docs/podbot-roadmap.md:0-0
Timestamp: 2026-06-01T18:40:34.207Z
Learning: Applies to docs/**/Makefile : E2E test suite must be separate from default `make test`, include JSON Lines preflight output, and enforce run-scoped isolation with unique `run_id` names

Learnt from: CR
Repo: leynos/nile-valley PR: 0
File: docs/opentofu-module-unit-testing-guide.md:0-0
Timestamp: 2026-01-31T13:38:15.688Z
Learning: Applies to docs/**/*.{tftest.hcl,tofutest.hcl} : Create separate `run` blocks for each significant conditional path in modules to test all branches of conditional logic

Learnt from: CR
Repo: leynos/shared-actions PR: 0
File: docs/rust-build-release-pipeline.md:0-0
Timestamp: 2026-05-10T12:33:50.444Z
Learning: Applies to docs/**/*.py : Move target validation and toolchain resolution into dedicated `action_setup.py` helper so composite actions can reuse logic and test suites can exercise failure modes directly

Learnt from: CR
Repo: leynos/prosidy-darn PR: 0
File: docs/roadmap.md:0-0
Timestamp: 2026-05-22T17:59:46.168Z
Learning: Applies to docs/**/*test*.py : Use `syrupy` snapshots for deterministic testing of `agent-context`, explanation output, JSONL cue sheets, SSML fragments, and Rich terminal output to ensure snapshot identifiers, timestamps, and generated unit IDs are stable across repeated runs

Learnt from: CR
Repo: leynos/concordat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T19:46:34.465Z
Learning: Applies to **/*.py : Python files must pass all relevant unit and behavioural tests (run `make test` to verify).

leynos added 2 commits June 4, 2026 19:28
Add a library target to generated application projects so `cargo test --doc`
has doctests to compile instead of failing on a binary-only package. Make the
rendered `make test` doctest invocation unconditional and extend the regression
test to cover both app and library flavours.
Move Act-enabled template tests into separate parent and rendered
`act-validation.yml` workflows. Keep the main CI workflows on the ordinary test
and coverage path so container-backed Act checks can run in parallel.
@leynos

leynos commented Jun 5, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following now been resolved?

tests/helpers/tooling_contracts.py (2)

406-415: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win
Guard uses with str() for consistency.
Line 122 already coerces uses via str(...) before .startswith, but here a uses: key set to null (a valid YAML value) returns None, and None.startswith(...) raises AttributeError instead of skipping the step. Match the safer pattern.

🛡️ Proposed fix
for step in job.get("steps", [])
         if isinstance(step, dict)
-        and step.get("uses", "").startswith("actions/checkout@")
+        and str(step.get("uses", "")).startswith("actions/checkout@")
     ]
🤖 Detailed instructions

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.py around lines 406 - 415, The
extract_checkout_steps function can raise AttributeError when a step's "uses"
value is None; change the predicate to guard by coercing uses to a string before
startswith — i.e., replace step.get("uses", "").startswith("actions/checkout@")
with str(step.get("uses", "")).startswith("actions/checkout@") so steps with
null/None uses are safely skipped; update the function extract_checkout_steps
accordingly.

74-91: 🧹 Nitpick | 🔵 Trivial | ⚖️ Poor tradeoff
Give the public helpers full numpy-style docstrings.
assert_generated_tooling_contracts and the other module-level (non-underscore) helpers carry only a single-line summary. Document the parameters and behaviour with a structured numpy block; reserve the single-line form for the private _assert_* helpers.
As per coding guidelines: "Docstrings must follow the numpy style guide. Use a single-line summary for private functions and methods, and full structured docs for all public interfaces."

🤖 Detailed instructions

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.py around lines 74 - 91, Public helpers like
assert_generated_tooling_contracts lack full numpy-style docstrings; replace the
single-line summary with a complete numpy-style docstring that includes a short
summary, Parameters (documenting each arg: package, metadata, flavour, makefile,
cargo_config, dev_target, rust_toolchain, parsed_ci_workflow, ci_workflow,
docs_contents, repository_layout, readme, test_stub, release_workflow and their
types/meanings), Returns (None), and any Raises/Notes describing behavior; leave
private helpers (those with leading underscores) as single-line summaries.
Locate assert_generated_tooling_contracts and other non-underscore module-level
helpers and update their docstrings accordingly to match the numpy style guide.

@leynos

leynos commented Jun 5, 2026

Copy link
Copy Markdown
Owner Author

@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.

❌ Failed checks (2 errors, 1 warning)

Check name Status Explanation Resolution
Testing (Overall) ❌ Error Review comment on line 13 of tests/test_helpers.py: aliased import import tests.utilities as utilities violates Ruff PLR0402 code quality guidance. Replace import tests.utilities as utilities with from tests import utilities on line 13.
Unit Architecture ❌ Error Import alias on line 13 of tests/test_helpers.py violates Ruff PLR0402: use from tests import utilities instead of import tests.utilities as utilities. Replace import tests.utilities as utilities with from tests import utilities on line 13 of tests/test_helpers.py to align with Ruff PLR0402 guidance on aliased module imports.
Developer Documentation ⚠️ Warning Unaddressed review comment on aliased import; new conftest fixtures and test modules not documented in developers-guide.md. Replace aliased import in tests/test_helpers.py and document new fixtures and integration test modules in docs/developers-guide.md.

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== Check if tooling_contracts is now a package ==="
ls -la tests/helpers/tooling_contracts/ 2>/dev/null || echo "DIRECTORY NOT FOUND"
ls tests/helpers/tooling_contracts.py 2>/dev/null || echo "FLAT FILE NOT FOUND"

echo ""
echo "=== extract_checkout_steps - find and show implementation ==="
rg -n "extract_checkout_steps\|startswith.*checkout\|uses.*checkout" tests/ -A3 -B1

echo ""
echo "=== Public function docstrings - assert_generated_tooling_contracts ==="
rg -n "def assert_generated_tooling_contracts\|def assert_documentation_navigation_contracts\|def assert_ci_coverage_action_contract\|def extract_checkout_steps" tests/ -A 15

Length of output: 1594


🏁 Script executed:

#!/bin/bash
echo "=== workflows.py - full content ==="
cat tests/helpers/tooling_contracts/workflows.py

echo ""
echo "=== orchestration.py - full content ==="
cat tests/helpers/tooling_contracts/orchestration.py

echo ""
echo "=== __init__.py - full content ==="
cat tests/helpers/tooling_contracts/__init__.py

Length of output: 14582



@leynos Yes, both are resolved.

Issue Status Evidence
str() guard on uses ✅ Resolved extract_checkout_steps in workflows.py uses str(step.get("uses", "")).startswith("actions/checkout@"), matching the safer pattern already used in assert_ci_coverage_action_contract.
Numpy-style docstrings on public helpers ✅ Resolved assert_ci_coverage_action_contract carries full Parameters / Returns / Raises blocks; extract_checkout_steps carries Parameters / Returns blocks; assert_generated_tooling_contracts carries Parameters / Returns / Raises / Notes blocks. All private _assert_* helpers retain single-line summaries.

@coderabbitai

This comment was marked as resolved.

Adapt the generated quality gate flow chart from the Python template README for
Rust projects. Show the generated Make targets, Rust lint/test/audit branches,
coverage upload path, and separate Act validation workflow.
@coderabbitai coderabbitai Bot added the Roadmap label Jun 5, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/developers-guide.md (1)

82-96: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Document new test modules and fixtures.

Add brief entries for the new test modules and fixtures introduced in this PR. Insert after line 96:

  • tests/conftest.py defines the act_ready fixture that probes container runtime availability before act-based workflow tests.
  • tests/test_parent_ci.py validates parent CI workflow contracts: main workflow excludes act setup; act-validation workflow includes act installation and WITH_ACT=1.
  • tests/test_github_actions_integration.py runs rendered act-validation workflows through act and asserts black-box Rust test execution evidence from JSON event logs.
📝 Proposed addition
 Container-aware support for optional `act` tests lives in `tests/utilities.py`.
 Direct helper edge-case tests live in `tests/test_helpers.py`; rendered project
 tests should use the shared helper APIs instead of reimplementing file parsing
 or workflow schema checks.
+
+Direct test modules for parent repository contracts:
+
+- `tests/conftest.py` defines the `act_ready` fixture that probes container
+  runtime availability before act-based workflow tests.
+- `tests/test_parent_ci.py` validates parent CI workflow contracts: main
+  workflow excludes act setup; act-validation workflow includes act
+  installation and WITH_ACT=1.
+- `tests/test_github_actions_integration.py` runs rendered act-validation
+  workflows through act and asserts black-box Rust test execution evidence
+  from JSON event logs.

As per coding guidelines, "New or changed internal APIs, architectural boundaries or abstractions, tooling or build requirements must be clearly documented in the developer's guide".

🤖 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 `@docs/developers-guide.md` around lines 82 - 96, Add documentation entries
after the existing Test Helper Layout section describing the new test modules
and fixtures: document that tests/conftest.py defines the act_ready fixture
which probes container runtime availability, tests/test_parent_ci.py validates
parent CI workflow contracts (main workflow excludes act setup; act-validation
workflow includes act installation and WITH_ACT=1), and
tests/test_github_actions_integration.py runs rendered act-validation workflows
through act and asserts black-box Rust test execution evidence from JSON event
logs; keep the style consistent with existing bullet entries in the Test Helper
Layout.
🤖 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 @.github/workflows/act-validation.yml:
- Around line 3-7: Add a top-level concurrency block to the workflow to prevent
redundant runs: under the workflow root (same level as the existing "on:" key)
add a "concurrency" key with a unique group identifier (for example using the
repo and branch/PR number or workflow name) and set "cancel-in-progress: true"
so any in-progress act-validation run is canceled when a newer run starts;
ensure the group string references context like github.ref or github.head_ref to
differentiate PRs/branches.

In `@README.md`:
- Around line 62-64: Add a comma after "workflow" in the sentence "Parent and
generated-project CI run this mode in a separate `act-validation.yml` workflow
so container-backed workflow checks run in parallel with the normal test and
coverage workflow." so it reads "... a separate `act-validation.yml` workflow,
so container-backed ..." to improve readability; update the README.md line
containing that sentence accordingly.

In `@template/docs/repository-layout.md.jinja`:
- Around line 73-74: The docs claim `src/lib.rs` "contains ... doctested
examples" but the generated `src/lib.rs` stub only defines `greet()` with no
doctest; either add a doctest example to the `greet()` function in `src/lib.rs`
(e.g., a /// doc comment with a code block showing `assert_eq!(greet(), "...")`)
or change the README line referencing `src/lib.rs` to say it "contains library
support for application logic with space for doctested examples" so the wording
matches the current stub.

In `@template/src/`{% if flavour == 'app' %}lib.rs{% endif %}.jinja:
- Around line 4-6: The greet() function lacks a doctest example as promised by
the docs; add a minimal doctest above pub const fn greet() that shows usage and
an assertion—include the Examples section and a fenced code block calling
greet() and asserting it equals "Hello from {{ project_name }}!" (use the crate
import form with {{ package_name }}::greet) so generated lib.rs demonstrates
doctest conventions.

In `@tests/helpers/tooling_contracts/makefile.py`:
- Line 12: The parameter "flavour" on _assert_makefile_contracts is unused;
either remove it from the function signature and from all callers (update the
call in the orchestration module that passes the flavour) or keep it and add a
short docstring/TODO explaining its reserved purpose and use it in future
flavour-specific checks; modify the function _assert_makefile_contracts and the
call site in the orchestration module accordingly so signatures match.

In `@tests/test_template/conftest.py`:
- Line 32: Update the write_fake_cargo fixture's return type to be explicit to
match cargo_metadata_for: change the annotation from Callable[..., Path] to
Callable[[Path, list[Path]], Path] so the factory signature is clear (or, if the
factory truly has a complex keyword-only signature with defaults, add a brief
inline comment on write_fake_cargo explaining why Callable[..., Path] is
intentionally used). Reference the write_fake_cargo fixture and
cargo_metadata_for for consistency.

In `@tests/test_template/test_snapshots.py`:
- Around line 43-52: The assertion message omits act_workflow while comparing
five keys; update the assertion's failure message to list all compared variables
(cargo_config, makefile, act_workflow, ci_workflow, release_workflow) so it
accurately reflects the comparison between the constructed dict and snapshot
used in the test (variables: cargo_config, makefile, act_workflow, ci_workflow,
release_workflow).

---

Outside diff comments:
In `@docs/developers-guide.md`:
- Around line 82-96: Add documentation entries after the existing Test Helper
Layout section describing the new test modules and fixtures: document that
tests/conftest.py defines the act_ready fixture which probes container runtime
availability, tests/test_parent_ci.py validates parent CI workflow contracts
(main workflow excludes act setup; act-validation workflow includes act
installation and WITH_ACT=1), and tests/test_github_actions_integration.py runs
rendered act-validation workflows through act and asserts black-box Rust test
execution evidence from JSON event logs; keep the style consistent with existing
bullet entries in the Test Helper Layout.
🪄 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: 80154a66-0f10-4d70-9975-c8a93cee1b9c

📥 Commits

Reviewing files that changed from the base of the PR and between 963d340 and 42c76dc.

📒 Files selected for processing (32)
  • .github/workflows/act-validation.yml
  • README.md
  • docs/developers-guide.md
  • docs/users-guide.md
  • template/.github/workflows/act-validation.yml
  • template/.github/workflows/ci.yml
  • template/Makefile.jinja
  • template/docs/developers-guide.md.jinja
  • template/docs/repository-layout.md.jinja
  • template/docs/users-guide.md.jinja
  • template/src/{% if flavour == 'app' %}lib.rs{% endif %}.jinja
  • tests/helpers/tooling_contracts/__init__.py
  • tests/helpers/tooling_contracts/cargo.py
  • tests/helpers/tooling_contracts/documentation.py
  • tests/helpers/tooling_contracts/makefile.py
  • tests/helpers/tooling_contracts/orchestration.py
  • tests/helpers/tooling_contracts/workflows.py
  • tests/test_github_actions_integration.py
  • tests/test_helpers.py
  • tests/test_parent_ci.py
  • tests/test_template.py
  • tests/test_template/__init__.py
  • tests/test_template/__snapshots__/test_snapshots.ambr
  • tests/test_template/conftest.py
  • tests/test_template/test_audit_targets.py
  • tests/test_template/test_basic_rendering.py
  • tests/test_template/test_compilation.py
  • tests/test_template/test_doctests.py
  • tests/test_template/test_lint_targets.py
  • tests/test_template/test_makefile_validation.py
  • tests/test_template/test_snapshots.py
  • tests/test_template/test_tooling_contracts.py
💤 Files with no reviewable changes (3)
  • template/.github/workflows/ci.yml
  • template/Makefile.jinja
  • tests/test_template.py

Comment thread .github/workflows/act-validation.yml
Comment thread README.md
Comment thread template/docs/repository-layout.md.jinja
Comment thread tests/helpers/tooling_contracts/makefile.py Outdated
Comment thread tests/test_template/conftest.py
Comment thread tests/test_template/test_snapshots.py
Use the preferred `from tests import utilities` import form in helper tests and
extend the developer guide test-helper layout with the Act fixture, rendered
workflow integration test, and parent CI contract test entrypoints.
@leynos

leynos commented Jun 5, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai pause

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews paused.

leynos added 3 commits June 5, 2026 12:33
Add concurrency cancellation to the parent Act validation workflow, document the
Act helper entrypoints more precisely, and add a doctest example to the
rendered app library stub. Remove the unused Makefile contract flavour
parameter and clarify the fake cargo fixture typing.
Set `RUSTFLAGS` to an empty value while generated CI installs cargo-nextest,
cargo-audit, and Whitaker so inherited compiler flags do not break tool
installation. Enforce the cleared environment in the rendered workflow
contract.
Move all parent and rendered workflow uses of `leynos/shared-actions` to
revision `455d9ed03477c0026da96c2541ca26569a74acac` and update the rendered
workflow contracts and snapshots that enforce the pin.
@leynos
leynos merged commit 2ce7051 into main Jun 6, 2026
5 checks passed
@leynos
leynos deleted the act-tests branch June 6, 2026 07:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant