Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
01b21aa
docs(quality): document Clippy allow rationale workflow
josecelano Sep 8, 2026
d534230
feat(quality): require documented Clippy allows
josecelano Sep 8, 2026
66eb585
docs(issues): format 2157 acceptance evidence
josecelano Sep 8, 2026
37e32e6
docs(issues): redefine 2157 Clippy allow policy
josecelano Sep 9, 2026
e44ae38
docs(issues): format 2157 replacement plan
josecelano Sep 9, 2026
4aebb83
refactor(quality): remove superseded Bash Clippy guard
josecelano Sep 9, 2026
d87a503
feat(quality): add native Clippy allow validator
josecelano Sep 9, 2026
be25519
docs(quality): document native Clippy allow validation
josecelano Sep 9, 2026
90113aa
fix(quality): emit structured Clippy validator diagnostics
josecelano Sep 9, 2026
8c4eab5
docs(quality): classify Clippy validator CLI output
josecelano Sep 9, 2026
94f2441
fix(container): include Clippy validator in recipe stage
josecelano Sep 9, 2026
43c9756
docs(issues): record 2157 container CI repair
josecelano Sep 9, 2026
361c183
fix(quality): parse validator arguments before Git access
josecelano Sep 9, 2026
5938a1e
fix(container): exclude Clippy validator from test archives
josecelano Sep 9, 2026
4002c89
docs(quality): record Clippy validator review fixes
josecelano Sep 9, 2026
8b5a994
docs(container): link workspace members to archive policy
josecelano Sep 9, 2026
cbbe0bd
docs(review): track PR 2177 remediation
josecelano Sep 10, 2026
9a376e4
docs(review): record PR 2177 Clippy fix progress
josecelano Sep 10, 2026
2e1231e
fix(quality): satisfy Clippy empty assertion lint
josecelano Sep 10, 2026
3754ea8
docs(review): record PR 2177 BB1 resolution
josecelano Sep 10, 2026
024fc78
fix(quality): harden Clippy validator Git diff parsing
josecelano Sep 10, 2026
62cba4f
docs(review): record PR 2177 diff hardening resolution
josecelano Sep 10, 2026
9b85a3e
fix(quality): validate Clippy expect reasons
josecelano Sep 10, 2026
7c8db51
docs(quality): document Clippy expect validation
josecelano Sep 10, 2026
d06a679
docs(review): record PR 2177 expect validation resolution
josecelano Sep 10, 2026
3f7636f
fix(quality): normalize temporary Clippy reasons
josecelano Sep 10, 2026
7efada9
docs(quality): clarify temporary Clippy reasons
josecelano Sep 11, 2026
f01bc84
docs(review): restore PR 2177 remediation evidence
josecelano Sep 11, 2026
19997ab
test(quality): cover accepted Clippy allow shapes
josecelano Sep 11, 2026
9b22ce3
docs(review): record PR 2177 allow shape coverage
josecelano Sep 11, 2026
a62d04a
docs(review): record PR 2177 output fallback progress
josecelano Sep 11, 2026
35b1c44
fix(quality): retain Clippy validator output errors
josecelano Sep 11, 2026
9cb37d5
docs(review): record PR 2177 validator test resolutions
josecelano Sep 11, 2026
2c70671
ci(testing): isolate documented Clippy allow validation
josecelano Sep 11, 2026
67d9801
fix(quality): validate staged Clippy allows
josecelano Sep 11, 2026
adf98fb
style(container): align nextest archive exclusions
josecelano Sep 11, 2026
faf3f34
docs(issue-2157): clarify review report append order
josecelano Sep 11, 2026
2b99357
docs(review): record PR 2177 maintainer resolutions
josecelano Sep 11, 2026
723b885
docs(review): finalize PR 2177 maintainer audit
josecelano Sep 11, 2026
ac19fe0
docs(review): record PR 2177 Copilot resolutions
josecelano Sep 11, 2026
287be93
docs(review): record PR 2177 consolidated replies
josecelano Sep 11, 2026
c74d894
style(docs): align PR 2177 review table
josecelano Sep 11, 2026
30b9cf8
fix(ci): repair rebase workflow regressions
josecelano Sep 14, 2026
ad5b6be
docs(issue-2157): record CI repair validation
josecelano Sep 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@
# ── Dev tooling (not needed in any build stage) ───────────────────────────────
# su-exec is compiled in the gcc stage: COPY ./contrib/dev-tools/su-exec/
# workspace-coupling/Cargo.toml is copied in the recipe stage for cargo chef prepare
# clippy-allow-reasons/Cargo.toml is copied in the recipe stage for cargo chef prepare
/contrib/dev-tools/
!/contrib/dev-tools/su-exec/
!/contrib/dev-tools/analysis/workspace-coupling/Cargo.toml
!/contrib/dev-tools/checks/clippy-allow-reasons/Cargo.toml

# ── Build artifacts and runtime state ─────────────────────────────────────────
/bin/
Expand Down
6 changes: 4 additions & 2 deletions .github/agents/clippy-fixer.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ You are the repository's Clippy warning fixer agent. Your job is to analyze clip

- Follow `AGENTS.md` for repository-wide behavior
- Always prefer applying clippy suggestions over adding `#[allow(...)]` attributes
- When allowances are needed, **always document the reason** in a clear comment
- For new or modified `#[allow(clippy::...)]` attributes, use a specific native
`reason = "..."` parameter. Temporary reasons also need a stable issue reference or explicit
non-empty removal condition.
- Create **atomic commits** for each clippy type warning (e.g., one commit per `explicit_iter_loop` issue)
- Link to the specific clippy warning in commit messages for traceability
- Use the `Committer` agent for final commits
Expand All @@ -23,7 +25,7 @@ You are the repository's Clippy warning fixer agent. Your job is to analyze clip
1. **Analyze clippy output**: Receive clippy warnings from user or `linter clippy`
2. **Identify fixable warnings**: Determine which warnings can be fixed with clippy suggestions
3. **Apply fixes**: Modify source code to apply clippy suggestions properly
4. **Document exceptions**: Add clear comments for any `#[allow(...)]` attributes
4. **Document exceptions**: Use the native `reason = "..."` parameter for changed Clippy allows
5. **Commit fixes**: Use `Committer` agent to create properly formatted commits
6. **Verify**: Ensure `linter all` passes after fixes

Expand Down
11 changes: 7 additions & 4 deletions .github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,13 @@ The script runs these steps in order:

1. `./contrib/dev-tools/git/format-project-words.sh` - formats `project-words.txt` with
`LC_ALL=C sort -u`
2. `cargo machete --with-metadata` - unused dependency check
3. `cargo deny check bans` - workspace layer-boundary dependency check
4. `linter all` - all linters (markdown, lychee local links, YAML, TOML, clippy, rustfmt, shellcheck, cspell)
5. `cargo test --doc --workspace` - documentation tests
2. `cargo run --quiet --package clippy-allow-reasons -- --staged` - prospective native-reason
check for changed staged Clippy allow attributes. The command resolves the first available
base reference from `origin/develop`, `upstream/develop`, `torrust/develop`, or local `develop`.
3. `cargo machete --with-metadata` - unused dependency check
4. `cargo deny check bans` - workspace layer-boundary dependency check
5. `linter all` - all linters (markdown, lychee local links, YAML, TOML, clippy, rustfmt, shellcheck, cspell)
6. `cargo test --doc --workspace` - documentation tests

If the formatter changes the dictionary, the hook exits non-zero before the verification steps.
Stage `project-words.txt` and retry the commit. Run the formatter independently with:
Expand Down
51 changes: 51 additions & 0 deletions .github/skills/dev/maintenance/add-workspace-member/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
name: add-workspace-member
description: Add or remove an explicit Cargo workspace member in Torrust Tracker. Use when editing the root workspace members list, adding a developer-tool crate, or registering a new standalone workspace package.
metadata:
author: torrust
version: "1.0"
semantic-links:
related-artifacts:
- Cargo.toml
- Containerfile
- .dockerignore
- .github/skills/dev/maintenance/add-rust-dependency/SKILL.md
---

# Add a Cargo Workspace Member

Use this workflow when changing the root `Cargo.toml` `[workspace].members` list. It applies to
explicit members only; path dependencies can be auto-discovered separately by Cargo.

## Required Review

1. Add or remove the member in root `Cargo.toml`.
2. Read the semantic link above that list and review `Containerfile` at the cargo-chef recipe
stage. Add or remove its manifest copy and all target stubs required by `cargo metadata`.
3. Decide whether the member has value in container test archives.
- Production-relevant members remain included.
- Developer-only analysis, checks, benchmarks, clients, and host-only E2E tools are normally
excluded from every `cargo nextest archive` invocation.
- Keep the explanation and all four archive exclusion lists synchronized.
4. Review `.dockerignore`; a manifest copied in the recipe stage must not be excluded from the
build context.

## Verification

Run the narrow validation appropriate to the change before the normal repository gate:

```bash
docker build --target recipe --file Containerfile .
```

For a changed archive inclusion/exclusion, also run:

```bash
docker build --target test_debug --file Containerfile .
```

Then run `linter all`, `cargo test --doc --workspace`, and the mandatory pre-commit workflow.

## Related Skills

- [`add-rust-dependency`](../add-rust-dependency/SKILL.md) — add an external dependency.
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,15 @@ git push {your-fork-remote} "$UPDATE_BRANCH"
2. Start from an up-to-date `develop` branch and create that dedicated branch.
3. Identify every matching action reference and review the action's release notes for compatibility or security implications. If no workflow reference needs an update, stop without committing.
4. Update all intended `.github/workflows/*.yaml` references consistently. Dependabot manages GitHub Actions updates through `.github/dependabot.yaml`; preserve its explicit version format.
5. Before opening the pull request, obtain the complete current Torrust organization allowed-actions list and save it in `"$ALLOWLIST_CURRENT"`. Prepare the complete revised list in `"$ALLOWLIST_NEW"`, retaining every current entry. The allowlist is organization-wide: never replace it with an inventory from this repository alone. A missing entry from the configured list may be authorized by a broader organization policy, such as GitHub-owned or verified Marketplace actions; do not infer that it must be added from a repository scan. If a complete replacement list is requested, obtain an organization-wide inventory first; otherwise, provide only the required additions and replacements. If the required reference is not allowed and the agent cannot change the organization policy, tell the user that a GitHub organization administrator must update the allowed-actions list before the workflow can run.
- Add an allowlist pattern that permits the versioned reference, such as `owner/action@v2.*`.
- Prefer a scoped, stable pattern over a moving `owner/action@v2` tag when Dependabot updates exact versions.
- Confirm that the configured pattern matches the full `uses:` reference, including its version.
- Compare the lists with a set-based comparison. Verification must prove that `"$ALLOWLIST_CURRENT"` is a subset of `"$ALLOWLIST_NEW"` for an additive change and that every third-party `uses:` reference is matched by the new list.
- Have an organization administrator apply the revised list at [Organization Actions settings](https://github.com/organizations/torrust/settings/actions), then confirm the update. Do not remove old entries merely because this repository no longer uses them; other Torrust repositories may still rely on them.
5. Before opening the pull request, obtain the complete current Torrust organization allowed-actions list and save it in `"$ALLOWLIST_CURRENT"`. Prepare the complete revised list in `"$ALLOWLIST_NEW"`, retaining every current entry. The allowlist is organization-wide: never replace it with an inventory from this repository alone. A missing entry from the configured list may be authorized by a broader organization policy, such as GitHub-owned or verified Marketplace actions; do not infer that it must be added from a repository scan. If a complete replacement list is requested, obtain an organization-wide inventory first; otherwise, provide only the required additions and replacements. If the required reference is not allowed and the agent cannot change the organization policy, tell the user that a GitHub organization administrator must update the allowed-actions list before the workflow can run. Add an allowlist pattern that permits the versioned reference, such as `owner/action@v2.*`, and prefer a scoped, stable pattern over a moving `owner/action@v2` tag when Dependabot updates exact versions. Confirm that the configured pattern matches the full `uses:` reference. Compare the lists with a set-based comparison: for an additive change, `"$ALLOWLIST_CURRENT"` must be a subset of `"$ALLOWLIST_NEW"`, and every third-party `uses:` reference must be matched by the new list. Have an organization administrator apply the revised list at [Organization Actions settings](https://github.com/organizations/torrust/settings/actions), then confirm the update. Do not remove old entries merely because this repository no longer uses them; other Torrust repositories may still rely on them.

6. Add one semantic `skill-link: update-github-workflow-actions` comment near the workflow's top-level metadata and review the related skills when updating the workflow policy.
7. Run `linter yaml`, `git diff --check`, and the mandatory pre-commit checks before committing.
8. Commit with a signed Conventional Commit and push the branch to the fork remote. When step 5 required an organization policy update, include the complete contents of both `"$ALLOWLIST_CURRENT"` and `"$ALLOWLIST_NEW"` verbatim in the commit body. Use headings that identify the lists as before and after the update; do not summarize or omit unchanged entries.
9. Open a PR targeting `develop` with [the GitHub workflow-actions update PR template](../../../../../docs/templates/GITHUB-WORKFLOW-ACTIONS-UPDATE-PR.md). Replace both allowlist placeholders with the complete captured contents verbatim. State the administrator's confirmation only when it was received.
10. Confirm affected workflow runs are queued and pass. If a run is blocked by the allowlist, correct the organization policy and rerun the failed jobs; do not weaken the workflow pin.
7. When a workflow command compares Git revisions, configure `actions/checkout` with
`fetch-depth: 0` so its merge base is available in CI.
8. Run `linter yaml`, `git diff --check`, and the mandatory pre-commit checks before committing.
9. Commit with a signed Conventional Commit and push the branch to the fork remote. When step 5 required an organization policy update, include the complete contents of both `"$ALLOWLIST_CURRENT"` and `"$ALLOWLIST_NEW"` verbatim in the commit body. Use headings that identify the lists as before and after the update; do not summarize or omit unchanged entries.
10. Open a PR targeting `develop` with [the GitHub workflow-actions update PR template](../../../../../docs/templates/GITHUB-WORKFLOW-ACTIONS-UPDATE-PR.md). Replace both allowlist placeholders with the complete captured contents verbatim. State the administrator's confirmation only when it was received.
11. Confirm affected workflow runs are queued and pass. If a run is blocked by the allowlist, correct the organization policy and rerun the failed jobs; do not weaken the workflow pin.

## Allowlist Failure Diagnosis

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,42 @@ Only add `#[allow(...)]` when:

## How to Document Exceptions

When adding `#[allow(...)]` attributes, always include a clear comment explaining why:
When adding or modifying `#[allow(clippy::...)]` or `#[expect(clippy::...)]` attributes, use Rust's
native `reason` parameter. The prospective Rust validator checks changed attributes against the
branch merge base, so existing allows remain the separate remediation scope of #2158.

```rust
// This is a temporary workaround during refactoring of the announce response parser
// TODO: Remove this allowance when the parser is fully refactored
#[allow(clippy::unnecessary_wraps)]
#[allow(
clippy::unnecessary_wraps,
reason = "Temporary parser compatibility shim; remove when #2158 is complete."
)]
```

The reason must be specific. A temporary reason must also contain either a stable issue reference
such as `#2158` or a non-empty `remove when`, `remove after`, `remove by`, `removed when`,
`removed after`, `removed by`, or `until` condition. The validator treats `temporary`,
`temporarily`, `TODO`, `for now`, and `workaround` as temporary wording and normalizes whitespace
before checking the condition.

Do not enable `clippy::allow_attributes_without_reason` workspace-wide until #2158 has remediated
the historical attributes that lack native reasons. It is the correct eventual compiler-aware
enforcement mechanism, but enabling it now would violate this issue's prospective-baseline scope.

For a temporary item-level suppression, prefer `#[expect(..., reason = "...")]` when it is useful
Comment thread
josecelano marked this conversation as resolved.
to learn that the underlying lint no longer fires. Do not force `expect` for crate-level policy.

The validator also checks changed `cfg_attr(..., allow(clippy::...))` and
`cfg_attr(..., expect(clippy::...))` controls. Attributes written inside a `macro_rules!` token body
are not visited by the Rust AST and are out of scope for this prospective check; do not use macros
to conceal a lint suppression.

For example:

```rust
#[expect(
clippy::unnecessary_wraps,
reason = "Temporary parser compatibility shim; remove when #2158 is complete."
)]
fn parse_announce_response(data: &[u8]) -> Result<Response, ParseError> {
// implementation
}
Expand Down Expand Up @@ -93,7 +123,7 @@ for item in &items {
1. **Identify the warning**: Run `linter clippy` to see specific clippy errors
2. **Apply suggestion**: Try the suggested fix first
3. **Verify functionality**: Ensure the change doesn't break existing behavior
4. **Document exceptions**: Add clear comments for any allowances
4. **Document exceptions**: Use the native `reason = "..."` parameter for changed Clippy allows
5. **Run full linters**: Confirm `linter all` passes

## Related Skills
Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/testing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,34 @@ jobs:
name: Run Unit Tests
run: cargo test --tests --benches --examples --workspace --all-targets --all-features

documented-clippy-allows:
name: Documented Clippy Allows
runs-on: ubuntu-latest
timeout-minutes: 15
env:
BASE_REF: ${{ github.base_ref || 'develop' }}

steps:
- id: checkout
name: Checkout Repository
uses: actions/checkout@v7.0.1
with:
fetch-depth: 0

- id: setup
name: Setup Toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable

- id: fetch-base
name: Fetch Base Branch
run: git fetch origin "$BASE_REF"

- id: check
name: Check Documented Clippy Allows
run: cargo run --quiet --package clippy-allow-reasons -- --base-ref "origin/$BASE_REF"

layer-bans:
name: Layer Boundary Bans
runs-on: ubuntu-latest
Expand Down
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,13 @@ url = { version = "2", features = [ "serde" ] }
nix = { version = "0.31.3", default-features = false, features = [ "signal" ] }

[workspace]
# skill-link: add-workspace-member
# related-artifact: Containerfile — when adding or removing an explicit member,
# review its cargo-chef manifest/stub lists and nextest archive exclusions.
members = [
"console/tracker-client",
"contrib/dev-tools/analysis/workspace-coupling",
"contrib/dev-tools/checks/clippy-allow-reasons",
"packages/e2e-tools",
"packages/persistence-benchmark",
"packages/rest-api-application",
Expand Down
Loading
Loading