Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a9c7aa6
ci(build): add Rust coverage workflow and codecov.yml mirroring upstr…
WilliamBerryiii Apr 25, 2026
d35e8f0
feat(ci): enforce rust crate registration in codecov coverage (#155)
WilliamBerryiii Apr 25, 2026
7a808d0
Merge remote-tracking branch 'github/main' into feat/issue-155-rust-c…
WilliamBerryiii Apr 26, 2026
870d0cd
fix(ci): make rust-tests reusable and wire into pr-validation and main
WilliamBerryiii Apr 26, 2026
918300c
fix(ci): register rust crate paths and correct matrix in reusable wor…
WilliamBerryiii Apr 26, 2026
9d35fe5
fix(ci): make rust-tests reusable-only by removing pull_request/push …
WilliamBerryiii Apr 26, 2026
7f40a2b
chore(scripts): relocate rust-crate-registration-report to logs/
WilliamBerryiii Apr 26, 2026
dd4375a
ci(rust): replace enterprise-blocked actions with shell equivalents a…
WilliamBerryiii Apr 27, 2026
3c632df
ci(rust-tests): install protoc and ffmpeg dev libs for candle-onnx/ff…
WilliamBerryiii Apr 27, 2026
15c5dfc
ci(rust-tests): add Syft SBOM + Grype scan for apt packages
WilliamBerryiii Apr 27, 2026
21af59a
Merge remote-tracking branch 'github/main' into feat/issue-155-rust-c…
WilliamBerryiii Apr 27, 2026
c118d32
fix(detect-changes): broaden Rust change-file regex to cover all src/…
WilliamBerryiii Apr 28, 2026
ce01b6e
chore(workflows): add matrix-folder-check docstring, refactor matrix-…
WilliamBerryiii Apr 28, 2026
a9f4ee9
chore(pester): default OutputPath to ./test-results
WilliamBerryiii Apr 28, 2026
e63cee9
feat(coverage): expand Rust coverage matrix to 9 crates and fix valid…
WilliamBerryiii Apr 28, 2026
005ecd1
fix(lint): rename Get-RustHasChanges to Test-RustHasChange
WilliamBerryiii Apr 28, 2026
685b62b
fix(workflows): use canonical tarball filenames for syft/grype sha256…
WilliamBerryiii Apr 28, 2026
eab9c58
fix(workflows): use Syft-compliant relative exclude patterns in rust-…
WilliamBerryiii Apr 28, 2026
076bde7
fix(ci): resolve rust test failures - add Array4 import, update topic…
WilliamBerryiii Apr 29, 2026
5b3e0fa
fix(clippy): gate Array4 import to test module
WilliamBerryiii Apr 29, 2026
1d4cdb1
fix(rust): correct alert topic detection and gate backend availabilit…
WilliamBerryiii Apr 29, 2026
05f6a05
ci(rust-tests): harden syft download with curl retries
WilliamBerryiii Apr 29, 2026
684e11c
ci(workflows): cache syft binary to mitigate transient GitHub release…
WilliamBerryiii Apr 29, 2026
d7984ff
fix(ci): apply .grype.yaml in vuln-scan via sparse checkout
WilliamBerryiii Apr 29, 2026
ff3ecef
chore(ci): narrow SBOM scan to repo sources
WilliamBerryiii Apr 30, 2026
18e085a
ci(rust-tests): remove continue-on-error from vuln-scan now that work…
WilliamBerryiii Apr 30, 2026
b70610f
Merge branch 'main' into feat/issue-155-rust-coverage-codecov
WilliamBerryiii Apr 30, 2026
e13b2fa
Merge branch 'main' into feat/issue-155-rust-coverage-codecov
WilliamBerryiii May 1, 2026
4037f46
Merge branch 'main' into feat/issue-155-rust-coverage-codecov
WilliamBerryiii May 1, 2026
6220d47
ci(rust-tests): retry apt-get to mitigate transient mirror DNS failures
WilliamBerryiii May 4, 2026
b414d14
Merge branch 'main' into feat/issue-155-rust-coverage-codecov
WilliamBerryiii May 4, 2026
7ec83aa
ci: name vuln-scan matrix entries by crate for clearer job labels
WilliamBerryiii May 5, 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: 1 addition & 1 deletion .github/ACTIONS-SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ All binary tool downloads in workflow steps must include SHA256 checksum verific
* Verify with `sha256sum --check --strict`
* Extract only after verification passes

Currently verified binaries: Gitleaks, Grype, TFLint.
Currently verified binaries: Gitleaks, Grype, Syft, TFLint.

## Permission Scoping

Expand Down
8 changes: 8 additions & 0 deletions .github/instructions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ Development standards and practices for C# code implementation.
- **Scope**: Code structure, naming conventions, best practices
- **Apply When**: Writing C# code in `**/*.cs` files

#### [Rust Crate Registration Instructions](rust-crate-registration.instructions.md)

Required registration of Rust crates under `src/500-application` for CI test/coverage and Codecov reporting.

- **Context**: Rust workspace coverage, CI matrix, Codecov flag mapping
- **Scope**: `rust-tests.yml` matrix and triggers, `codecov.yml` flags and ignore lists, opt-out path
- **Apply When**: Adding, restructuring, or removing crates under `**/src/500-application/**/Cargo.toml`, or editing `**/.github/workflows/rust-tests.yml` or `**/codecov.yml`

### Scripting and Automation

#### [Bash Instructions](bash.instructions.md)
Expand Down
130 changes: 130 additions & 0 deletions .github/instructions/rust-crate-registration.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
---
description: 'Required registration of Rust crates under src/500-application for CI test/coverage and Codecov reporting - Brought to you by microsoft/edge-ai'
applyTo: '**/src/500-application/**/Cargo.toml,**/.github/workflows/rust-tests.yml,**/.github/workflows/pr-validation.yml,**/scripts/build/Detect-Folder-Changes.ps1,**/codecov.yml'
---

# Rust Crate Registration Instructions

These rules govern how Rust application crates under `src/500-application/**` are registered with CI and Codecov. They complement the broader Rust guidance in [.github/instructions/rust.instructions.md](.github/instructions/rust.instructions.md) ("Workspace Architecture" section) and are enforced by an automated CI gate (see "CI Gate" below).

Every Rust crate under `src/500-application/**` MUST be either:

1. **Registered for coverage** in all three locations described in [Required Registration](#required-registration), OR
2. **Explicitly opted out** via the [Coverage Opt-Out](#coverage-opt-out) path in `codecov.yml`.

There is no third option. PRs that add or restructure a Rust crate without satisfying one of the above will fail the `validate-rust-registration` CI gate.

<!-- <rust-crate-registration-instructions> -->

## Required Registration

When a Rust crate participates in coverage, it MUST be registered in **all three** of the following locations. Missing any one of them is a CI failure.

### 1. `.github/workflows/rust-tests.yml` matrix

Add the crate as an `include:` entry under `jobs.coverage.strategy.matrix`. Each entry is an object with a `crate` path and optional `system_deps` for extra apt packages:

```yaml
jobs:
coverage:
strategy:
matrix:
include:
- crate: src/500-application/503-media-capture-service/services/media-capture-service
system_deps: ffmpeg # optional: extra apt packages installed before build
- crate: src/500-application/507-ai-inference/services/ai-edge-inference
- crate: src/500-application/507-ai-inference/services/ai-edge-inference-crate
- crate: src/500-application/NNN-your-new-crate/services/your-service # <-- add here
```

The `crate` value MUST be the directory containing the crate's `Cargo.toml`. When adding an entry, also bump the `vuln-scan` job's `matrix.index` array so its length matches the number of `include:` entries (zero-based indices).

### 2. `scripts/build/Detect-Folder-Changes.ps1` change-detection regex

`rust-tests.yml` is a reusable workflow (`on: workflow_call`) and has no path triggers of its own. It is invoked by the `rust-tests` job in `pr-validation.yml`, which is gated by the `changesInRust` output of the shared `matrix-changes` job (the reusable `matrix-folder-check.yml` workflow). That output is computed by `scripts/build/Detect-Folder-Changes.ps1`, which matches the diffed PR file list against this regex:

```text
^src/500-application/ # any path under this prefix
^Cargo\.toml$
^Cargo\.lock$
^\.github/workflows/rust-tests\.yml$
^\.github/workflows/pr-validation\.yml$
^codecov\.yml$
```
Comment thread
WilliamBerryiii marked this conversation as resolved.

Any crate located under `src/500-application/` is already covered by the `^src/500-application/` prefix and requires **no change** to this filter. Only extend the filter when a crate lives outside that prefix; in that case add a matching condition to the `$rustChangeFiles` block in `scripts/build/Detect-Folder-Changes.ps1` (for example `$_ -match '^src/600-other-area/'`).

### 3. `codecov.yml` rust flag paths

Add a glob covering the crate to `flags.rust.paths` so Codecov associates uploaded coverage with the `rust` flag:

```yaml
flags:
rust:
paths:
- "src/500-application/503-media-capture-service/**"
- "src/500-application/507-ai-inference/**"
- "src/500-application/NNN-your-new-crate/**" # <-- add here
carryforward: true
```

## Coverage Opt-Out

Crates that are intentionally excluded from coverage (for example, experimental scaffolding, WASM operators with no host-side test surface, or crates pending refactor) MUST be listed in `codecov.yml` under `ignore`:

```yaml
ignore:
- "src/500-application/512-avro-to-json/**"
- "src/500-application/NNN-your-new-crate/**" # <-- opt out here
- "target/**"
```

When a crate is listed under `ignore`, it MUST NOT appear in the `rust-tests.yml` matrix or in `flags.rust.paths`. The CI gate treats ignored crates as fully satisfying the registration requirement.

## CI Gate

The workflow `.github/workflows/validate-rust-registration.yml` runs the script `scripts/Validate-RustCrateRegistration.ps1` on every PR that touches `src/500-application/**`, `.github/workflows/rust-tests.yml`, `codecov.yml`, or the validator itself. The gate fails the build with an itemized report when any crate under `src/500-application/**` is neither fully registered (all three locations) nor explicitly opted out.

## Local Validation

Run before opening a PR:

```pwsh
pwsh ./scripts/Validate-RustCrateRegistration.ps1
```

Tests live in `scripts/Validate-RustCrateRegistration.Tests.ps1` and are gated by `.github/workflows/validate-rust-registration.yml` on PR.

## Example: Adding a New Crate

For a hypothetical new crate at `src/500-application/520-example-service` (under the existing `src/500-application/` prefix), only the matrix and the Codecov flag paths need updating; the `pr-validation.yml` regex already matches:

```diff
# .github/workflows/rust-tests.yml
matrix:
include:
- crate: src/500-application/503-media-capture-service/services/media-capture-service
system_deps: ffmpeg
- crate: src/500-application/507-ai-inference/services/ai-edge-inference
- crate: src/500-application/507-ai-inference/services/ai-edge-inference-crate
+ - crate: src/500-application/520-example-service/services/example
```

Also bump the `vuln-scan` job's `matrix.index` array length to match the new `include:` entry count.

```diff
# codecov.yml
flags:
rust:
paths:
- "src/500-application/503-media-capture-service/**"
- "src/500-application/507-ai-inference/**"
+ - "src/500-application/520-example-service/**"
carryforward: true
```

If a future crate lives outside `src/500-application/`, also extend the rust-change filter in `scripts/build/Detect-Folder-Changes.ps1` so its path triggers the `rust-tests` job via the `matrix-changes` `changesInRust` output.

To opt out instead, omit both diffs above and add a single `ignore` entry to `codecov.yml`.

<!-- </rust-crate-registration-instructions> -->
9 changes: 5 additions & 4 deletions .github/workflows/application-matrix-builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -359,14 +359,15 @@ jobs:
# Install Grype vulnerability scanner pinned to a release tag with checksum verification
GRYPE_VERSION="v0.86.1"
GRYPE_VER="${GRYPE_VERSION#v}"
GRYPE_TARBALL="grype_${GRYPE_VER}_linux_amd64.tar.gz"
GRYPE_TMP="$(mktemp -d)"
echo "Installing Grype ${GRYPE_VERSION}..."
curl -sSfL -o "${GRYPE_TMP}/grype.tar.gz" \
"https://github.com/anchore/grype/releases/download/${GRYPE_VERSION}/grype_${GRYPE_VER}_linux_amd64.tar.gz"
curl -sSfL -o "${GRYPE_TMP}/${GRYPE_TARBALL}" \
"https://github.com/anchore/grype/releases/download/${GRYPE_VERSION}/${GRYPE_TARBALL}"
curl -sSfL -o "${GRYPE_TMP}/grype_checksums.txt" \
"https://github.com/anchore/grype/releases/download/${GRYPE_VERSION}/grype_${GRYPE_VER}_checksums.txt"
(cd "${GRYPE_TMP}" && grep " grype_${GRYPE_VER}_linux_amd64.tar.gz$" grype_checksums.txt | sha256sum -c -)
sudo tar -xzf "${GRYPE_TMP}/grype.tar.gz" -C /usr/local/bin grype
(cd "${GRYPE_TMP}" && grep " ${GRYPE_TARBALL}$" grype_checksums.txt | sha256sum -c -)
sudo tar -xzf "${GRYPE_TMP}/${GRYPE_TARBALL}" -C /usr/local/bin grype
rm -rf "${GRYPE_TMP}"

echo "Verifying Grype installation..."
Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,15 @@ jobs:
break-build: true
secrets: inherit

# Rust unit/integration tests with coverage for main branch
rust-tests-main:
name: Rust Tests
permissions:
contents: read
id-token: write
uses: ./.github/workflows/rust-tests.yml
secrets: inherit

# Dependency advisory audit (cargo-audit + govulncheck) for main branch
dep-audit-main:
name: Dependency Audit
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/matrix-folder-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
# - changedBicepFolders: JSON object with all identified Bicep folder names for matrix strategy
# - changesInApplications: true/false indicating if any Application folders have changed (when includeApplications=true)
# - changedApplicationFolders: JSON object with Application folder details for matrix strategy (when includeApplications=true)
# - changesInRust: true/false indicating if any Rust-related files have changed (gates the rust-tests workflow)
#
# Usage Examples:
# ```yaml
Expand Down Expand Up @@ -123,6 +124,9 @@ on: # yamllint disable-line rule:truthy
changedApplicationFolders:
description: 'JSON matrix of Application folders that have changed'
value: ${{ jobs.map-outputs.outputs.changedApplicationFolders }}
changesInRust:
description: 'Whether any Rust-relevant files have changed (gates rust-tests)'
value: ${{ jobs.map-outputs.outputs.changesInRust }}

permissions:
contents: read # Read repository contents and git history for change detection
Expand All @@ -140,6 +144,7 @@ jobs:
changedBicepFolders: ${{ steps.detect.outputs.changedBicepFolders }}
changesInApplications: ${{ steps.detect.outputs.changesInApplications }}
changedApplicationFolders: ${{ steps.detect.outputs.changedApplicationFolders }}
changesInRust: ${{ steps.detect.outputs.changesInRust }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand Down Expand Up @@ -178,6 +183,7 @@ jobs:
"changedBicepFolders=$($jsonData.bicep.folders | ConvertTo-Json -Compress)" >> $env:GITHUB_OUTPUT
"changesInApplications=$($jsonData.applications.has_changes)" >> $env:GITHUB_OUTPUT
"changedApplicationFolders=$($jsonData.applications.folders | ConvertTo-Json -Compress)" >> $env:GITHUB_OUTPUT
"changesInRust=$($jsonData.rust.has_changes)" >> $env:GITHUB_OUTPUT

# Display results for debugging
Write-Host "Detection results:"
Expand All @@ -189,6 +195,7 @@ jobs:
Write-Host "Bicep folders: $($jsonData.bicep.folders | ConvertTo-Json)"
Write-Host "Application changes: $($jsonData.applications.has_changes)"
Write-Host "Application folders: $($jsonData.applications.folders | ConvertTo-Json)"
Write-Host "Rust changes: $($jsonData.rust.has_changes)"

# Map outputs from the detection job to maintain backward compatibility
map-outputs:
Expand All @@ -203,6 +210,7 @@ jobs:
changedBicepFolders: ${{ needs.detect-changes.outputs.changedBicepFolders }}
changesInApplications: ${{ needs.detect-changes.outputs.changesInApplications }}
changedApplicationFolders: ${{ needs.detect-changes.outputs.changedApplicationFolders }}
changesInRust: ${{ needs.detect-changes.outputs.changesInRust }}
steps:
- name: Map outputs for backward compatibility
run: echo "Mapping outputs from detection job for backward compatibility"
16 changes: 15 additions & 1 deletion .github/workflows/pr-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,20 @@ jobs:
break-build: true
secrets: inherit

# Rust unit/integration tests with coverage for PRs
# Gated on Rust-relevant changes via the shared matrix-changes detection job
# (changesInRust output) to avoid running the expensive coverage matrix on
# PRs that touch no Rust crates, manifests, or rust-tests workflow files.
rust-tests:
name: Rust Tests
needs: [matrix-changes]
if: github.event_name != 'pull_request' || needs.matrix-changes.outputs.changesInRust == 'true'
permissions:
contents: read
id-token: write
Comment thread
WilliamBerryiii marked this conversation as resolved.
uses: ./.github/workflows/rust-tests.yml
secrets: inherit

# Dependency advisory audit (cargo-audit + govulncheck) for PRs
dep-audit:
name: Dependency Audit
Expand Down Expand Up @@ -339,7 +353,7 @@ jobs:

- name: Upload Test Results
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: pester-test-results
path: test-results/
Expand Down
Loading
Loading