build(build): add clippy lint configuration and CI integration#231
build(build): add clippy lint configuration and CI integration#231WilliamBerryiii wants to merge 2 commits intomainfrom
Conversation
- add [lints.clippy] to all 13 Rust crate Cargo.toml files - create AzDO and GitHub Actions reusable clippy CI templates - integrate clippy into PR and Main pipeline stages - handle WASM crates with --target wasm32-wasip2 🔧 - Generated by Copilot
There was a problem hiding this comment.
Pull request overview
This PR adds Rust clippy lint enforcement to all 13 Rust crates in the repository and integrates clippy checks into both GitHub Actions and Azure DevOps CI pipelines. It fulfills the OSSF Silver warnings_strict criterion (issue #169) by configuring per-crate [lints.clippy] sections in each Cargo.toml and creating reusable CI templates that auto-detect WASM vs. native crates.
Changes:
- Added consistent
[lints.clippy]configuration to all 13 Rust crateCargo.tomlfiles (correctness = deny,suspicious/complexity/style/perf = warn), withmissing_safety_doc = "allow"for the three WASMcdylibcrates - Created reusable CI templates for both GitHub Actions (
.github/workflows/rust-clippy.yml) and Azure DevOps (.azdo/templates/rust-clippy-template.yml) that iterate all crates and auto-detect WASM targets - Integrated the clippy checks into
pr-validation.yml(blocking),main.yml(warning-only), andazure-pipelines.yml(both Main and PR stages)
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
.github/workflows/rust-clippy.yml |
New reusable GitHub Actions workflow for running clippy across all Rust crates |
.github/workflows/pr-validation.yml |
Adds rust-clippy job (blocking) after mega-linter |
.github/workflows/main.yml |
Adds rust-clippy-main job (warning-only) after mega-linter |
.azdo/templates/rust-clippy-template.yml |
New AzDO reusable job template for clippy with private registry auth |
azure-pipelines.yml |
Integrates clippy template into both Main and PR pipeline stages |
src/500-application/501-rust-telemetry/services/sender/Cargo.toml |
Adds [lints.clippy] section (5 category rules) |
src/500-application/501-rust-telemetry/services/receiver/Cargo.toml |
Adds [lints.clippy] section (5 category rules) |
src/500-application/502-rust-http-connector/services/broker/Cargo.toml |
Adds [lints.clippy] section (5 category rules) |
src/500-application/502-rust-http-connector/services/subscriber/Cargo.toml |
Adds [lints.clippy] section (5 category rules) |
src/500-application/503-media-capture-service/services/media-capture-service/Cargo.toml |
Adds [lints.clippy] section (5 category rules) |
src/500-application/504-mqtt-otel-trace-exporter/services/mqtt-otel-trace-exporter/Cargo.toml |
Adds [lints.clippy] section (5 category rules) |
src/500-application/507-ai-inference/services/ai-edge-inference/Cargo.toml |
Adds [lints.clippy] section (5 category rules) |
src/500-application/507-ai-inference/services/ai-edge-inference-crate/Cargo.toml |
Adds [lints.clippy] section (5 category rules) |
src/500-application/507-ai-inference/services/ai-edge-inference-crate/tests/no-features-test/Cargo.toml |
Adds [lints.clippy] section (5 category rules) |
src/500-application/511-rust-embedded-wasm-provider/operators/custom-provider/Cargo.toml |
Adds [lints.clippy] section with missing_safety_doc = "allow" for WASM crate |
src/500-application/511-rust-embedded-wasm-provider/operators/map/Cargo.toml |
Adds [lints.clippy] section with missing_safety_doc = "allow" for WASM crate |
src/500-application/512-avro-to-json/operators/avro-to-json/Cargo.toml |
Adds [lints.clippy] section with missing_safety_doc = "allow" for WASM crate |
src/900-tools-utilities/901-video-tools/cli/video-to-gif/Cargo.toml |
Adds [lints.clippy] section (5 category rules) |
| if [ -n "$(System.PullRequest.SourceBranch)" ]; then | ||
| git checkout "$(System.PullRequest.SourceBranch)" | ||
| fi | ||
| condition: and(succeeded(), ne(variables['System.PullRequest.SourceBranch'], '')) |
There was a problem hiding this comment.
The PR source branch checkout pattern deviates from the established convention used by all other AzDO templates in this repository. Every other template (e.g., checkov-template.yml:54-63, aio-version-checker-template.yml:83-92, megalinter-template.yml:115, etc.) uses:
condition: eq(variables['Build.Reason'], 'PullRequest')
with the script pattern:
BRANCH_NAME=$(echo "$(System.PullRequest.SourceBranch)" | sed 's|^refs/heads/||')
echo "Switching to PR source branch HEAD: $BRANCH_NAME"
git checkout "$BRANCH_NAME"
git log -1 --onelineThis template should follow the same pattern for consistency: use eq(variables['Build.Reason'], 'PullRequest') as the condition, strip the refs/heads/ prefix from the branch name, and include the informational log messages.
| if [ -n "$(System.PullRequest.SourceBranch)" ]; then | |
| git checkout "$(System.PullRequest.SourceBranch)" | |
| fi | |
| condition: and(succeeded(), ne(variables['System.PullRequest.SourceBranch'], '')) | |
| BRANCH_NAME=$(echo "$(System.PullRequest.SourceBranch)" | sed 's|^refs/heads/||') | |
| echo "Switching to PR source branch HEAD: $BRANCH_NAME" | |
| git checkout "$BRANCH_NAME" | |
| git log -1 --oneline | |
| condition: eq(variables['Build.Reason'], 'PullRequest') |
| targetType: inline | ||
| script: | | ||
| curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable -c clippy | ||
| echo "##vso[task.prependpath]$HOME/.cargo/bin" |
There was a problem hiding this comment.
The ##vso[task.prependpath] command on line 69 only updates PATH for subsequent Azure DevOps tasks, not the currently running script. Since rustup.rs installs to $HOME/.cargo/bin and a Bash@3 task runs in a non-interactive non-login shell (so ~/.bashrc/~/.profile are not sourced), the rustup binary will not be in PATH when line 70 executes.
To fix this, source the cargo environment before calling rustup, for example by adding source "$HOME/.cargo/env" between lines 69 and 70, or by using the full path "$HOME/.cargo/bin/rustup" target add wasm32-wasip2.
| echo "##vso[task.prependpath]$HOME/.cargo/bin" | |
| echo "##vso[task.prependpath]$HOME/.cargo/bin" | |
| source "$HOME/.cargo/env" |
| - name: Run Clippy on all Rust crates | ||
| shell: bash | ||
| env: | ||
| BREAK_BUILD: ${{ inputs.break_build }} | ||
| run: | | ||
| set -euo pipefail | ||
| FAILED=0 | ||
| for cargo_toml in $(find src/ -name "Cargo.toml" -not -path "./Cargo.toml"); do | ||
| crate_dir=$(dirname "$cargo_toml") | ||
| echo "::group::Clippy: $crate_dir" | ||
| if grep -q 'crate-type.*=.*\["cdylib"\]' "$cargo_toml"; then | ||
| echo "WASM crate detected — using --target wasm32-wasip2" | ||
| (cd "$crate_dir" && cargo clippy --target wasm32-wasip2 -- -D warnings) || FAILED=1 | ||
| else | ||
| (cd "$crate_dir" && cargo clippy -- -D warnings) || FAILED=1 | ||
| fi |
There was a problem hiding this comment.
The GitHub Actions workflow doesn't configure CARGO_REGISTRIES_AIO_SDKS_TOKEN for the clippy step, but multiple crates (including custom-provider, map, avro-to-json, broker, subscriber, sender, receiver, media-capture-service, mqtt-otel-trace-exporter, and ai-edge-inference) depend on the aio-sdks private registry. The AzDO template correctly sets this via env: CARGO_REGISTRIES_AIO_SDKS_TOKEN (line 95 of rust-clippy-template.yml), but the GitHub Actions workflow is missing this configuration.
Without this token, cargo clippy will fail when resolving dependencies from the aio-sdks registry. You should add CARGO_REGISTRIES_AIO_SDKS_TOKEN as an environment variable to the "Run Clippy" step, sourced from a secret, and also declare it in the workflow_call secrets section (or rely on secrets: inherit and reference the secret directly).
.github/workflows/rust-clippy.yml
Outdated
| fetch-depth: 0 | ||
|
|
||
| - name: Install Rust toolchain and clippy | ||
| uses: dtolnay/rust-toolchain@stable |
There was a problem hiding this comment.
Should we use a commit SHA here instead of mutable floating tag stable? The latest stable commit appears to be 631a55b12751854ce901bb631d5902ceb48146f7
- add CARGO_REGISTRIES_AIO_SDKS_TOKEN to GitHub Actions workflow env - fix PATH for rustup in AzDO template install task - pin dtolnay/rust-toolchain to commit SHA 🔧 - Generated by Copilot
Description
Added per-crate
[lints.clippy]configuration to all 13 Rust crates and created dedicated CI pipeline templates for both Azure DevOps and GitHub Actions to enforce clippy lints on pull requests, fulfilling the OSSF Silver warnings_strict criterion.CI Templates
Two reusable CI templates were created with matching behavior — each iterates all Rust crates under src/, auto-detects WASM crates via
cdylibcrate-type, and applies--target wasm32-wasip2for those crates..azdo/templates/rust-clippy-template.ymlas an Azure DevOps reusable job template with configurabledependsOn,displayName,condition, andagentPoolparametersaio-sdksprivate registry authentication viaCARGO_REGISTRIES_AIO_SDKS_TOKENenvironment variable.github/workflows/rust-clippy.ymlas a GitHub Actions reusable workflow with abreak_buildparameter controlling fail vs. warn behaviordtolnay/rust-toolchain@stableaction and pinnedactions/checkoutcommit hashPipeline Integration
Integrated the clippy templates into all CI stages across both platforms.
rust-clippyjob to.github/workflows/pr-validation.ymlwithbreak_build: true(blocking on PRs), running aftermega-linterrust-clippy-mainjob to.github/workflows/main.ymlwithbreak_build: false(warning-only on main), running aftermega-linterrust-clippy-template.ymlinto both Main and PR stages ofazure-pipelines.ymlCargo.toml Lint Configuration
Applied consistent
[lints.clippy]sections to all 13 Rust crate Cargo.toml files with five category-level rules.denyand suspicious, complexity, style, perf aswarnacross all cratesmissing_safety_doc = "allow"for the three WASMcdylibcrates (custom-provider, map, avro-to-json) where FFI boundaries make safety docs impractical[lints.clippy]sections consistently before[profile.release]or[workspace]following Cargo.toml conventionsRelated Issue
Closes #169
Type of Change
Implementation Details
The approach uses Cargo's native
[lints.clippy]table (stabilized in Rust 1.74) rather than workspace-level[workspace.lints]inheritance, since the 13 crates are independent (separate[workspace]declarations, no shared workspace root). Each crate's Cargo.toml declares lint severity per category group withpriority = -1to ensure category-level rules apply before individual lint overrides.WASM crates targeting
wasm32-wasip2received an additionalmissing_safety_doc = "allow"because their FFI boundary code usesunsafeblocks where safety documentation is not applicable.Both CI templates share identical crate-iteration logic:
find src/ -name "Cargo.toml", then grep forcdylibcrate-type to determine whether--target wasm32-wasip2is needed. The GitHub Actions variant addsbreak_buildconditional logic for fail vs. warn behavior.Testing Performed
Validation Steps
custom-provider,map,avro-to-json) run with--target wasm32-wasip2Checklist
terraform fmton all Terraform codeterraform validateon all Terraform codeaz bicep formaton all Bicep codeaz bicep buildto validate all Bicep codemega-linter-runner)Additional Notes
RUST_CLIPPYto MegaLinter due to incompatibility with the multi-crate, multi-target structure of the repository.rssource files were modified — this is purely configuration and CI infrastructure901-video-toolscrate undersrc/900-tools-utilities/was included despite being outside the500-application/matrix detection scope, ensuring full crate coverage