dotnet / dotnet/maui

[Infra] cgmanifest.json generation drops SQLitePCLRaw registration; checked-in manifest is stale and guidance is contradictory

Open
#36,948 0 comments 1 reaction 0 assignees View on GitHub
s/triaged
Dominant language
C#
Stars
23.3k
Forks
2k
Avg merge
1d 10h
Merged PRs (30d)
297

Description

### Description

The Component Governance manifest infrastructure for `src/Templates/src/cgmanifest.json` has a concrete dependency-coverage bug plus several process/documentation issues that make it easy for the manifest to drift.

## 1. Concrete bug: SQLitePCLRaw is dropped by regeneration

`eng/scripts/update-cgmanifest.ps1` maps:

```powershell
'SQLitePCLRaw.bundle_e_sqlite3' = 'SQLitePCLRawBundleESqlite3PackageVersion'
```

at `eng/scripts/update-cgmanifest.ps1:60`, but there is no `SQLitePCLRawBundleESqlite3PackageVersion` in `eng/Versions.props`. The only related property I found is `SQLitePCLRawBundleGreenPackageVersion` at `eng/Versions.props:171`.

I verified the template dependency with grep on both this PR branch and `origin/net11.0`: `src/Templates/src/templates/maui-mobile/MauiApp.1.csproj:86` references:

```xml

```

Running the generator prints:

```text
WARNING: Could not find version for SQLitePCLRaw.bundle_e_sqlite3 (property: SQLitePCLRawBundleESqlite3PackageVersion)
```

and emits no registration for that package. Because the script then replaces the whole registrations array (`eng/scripts/update-cgmanifest.ps1:146`), the checked-in `SQLitePCLRaw.bundle_green` entry at `src/Templates/src/cgmanifest.json:116-117` is deleted on regeneration, but no `SQLitePCLRaw.bundle_e_sqlite3` entry is added.

So today the checked-in manifest has a stale/wrong SQLite package (`SQLitePCLRaw.bundle_green` `2.1.10`), while the package actually used by the template (`SQLitePCLRaw.bundle_e_sqlite3` `3.0.3`) is not represented after generation.

## 2. Documentation bug: docs say manual entries are preserved, but the script replaces everything

`docs/CgManifest.md:108` says:

> If you need to manually add packages that aren't in `Versions.props`, you can edit the `cgmanifest.json` file directly. The update scripts preserve manually added entries and only update versions for packages it knows about.

That is not what the script does. It builds a new list and assigns it wholesale:

```powershell
$cgManifest.registrations = $sortedRegistrations
```

at `eng/scripts/update-cgmanifest.ps1:146`.

This makes the SQLitePCLRaw issue more dangerous: contributors are told direct edits are preserved, but regeneration silently removes any entry not backed by the script/version mapping.

There is also a small typo at `docs/CgManifest.md:18`: `dotnet tool resotre` should be `dotnet tool restore`.

## 3. The checked-in manifest is stale on `net11.0`

I backed up `src/Templates/src/cgmanifest.json`, ran:

```bash
pwsh -NonInteractive -ExecutionPolicy Bypass -File eng/scripts/update-cgmanifest.ps1
```

then restored the file. The generated manifest differed from the committed file (`1 file changed, 26 insertions(+), 17 deletions(-)` on the current #35950 branch, which already adds Avalonia registrations). Meaningful drift included:

| Package | Checked-in `src/Templates/src/cgmanifest.json` | Generated from `eng/Versions.props` |
| --- | --- | --- |
| `Microsoft.Extensions.Configuration` | `10.0.0` (`cgmanifest.json:53-54`) | `11.0.0-preview.7.26365.101` |
| `Microsoft.Extensions.DependencyInjection` | `10.0.0` (`cgmanifest.json:62-63`) | `11.0.0-preview.7.26365.101` |
| `Microsoft.Extensions.Logging.Debug` | `10.0.0` (`cgmanifest.json:71-72`) | `11.0.0-preview.7.26365.101` |
| `Microsoft.WindowsAppSDK` | `1.8.251106002` (`cgmanifest.json:107-108`) | `2.3.1` |
| `Microsoft.Graphics.Win2D` | `1.3.2` (`cgmanifest.json:80-81`) | `1.4.0` |
| `Microsoft.Windows.SDK.BuildTools` | `10.0.26100.4654` (`cgmanifest.json:98-99`) | `10.0.28000.2526` |
| `xunit` | `2.9.0` (`cgmanifest.json:134-135`) | `2.9.3` |
| `xunit.analyzer` | `1.15.0` (`cgmanifest.json:143-144`) | `1.18.0` |
| `SQLitePCLRaw.bundle_green` | `2.1.10` (`cgmanifest.json:116-117`) | deleted, and no `SQLitePCLRaw.bundle_e_sqlite3` replacement is emitted |

## 4. Nothing appears to keep the checked-in copy in sync, and it may not need to be checked in

`eng/CgManifest.targets` is imported at the top of `src/Templates/src/Microsoft.Maui.Templates.csproj` (`Microsoft.Maui.Templates.csproj:3`). Its `UpdateCgManifest` target runs before build by default:

- `eng/CgManifest.targets:15` defaults `UpdateCgManifestBeforeBuild` to `true`.
- `eng/CgManifest.targets:24` runs `UpdateCgManifest` `BeforeTargets="BeforeBuild"`.
- `src/Templates/src/Microsoft.Maui.Templates.csproj:148` also sets `UpdateCgManifestBeforeBuild` to `true`.

That means template builds regenerate the file on disk, but the generated working-tree change is thrown away unless a human notices and commits it. I did not find a workflow/pipeline under `.github/workflows` or `eng/pipelines` that sets `GenerateCgManifest=true` or gates on `src/Templates/src/cgmanifest.json` being clean after regeneration.

Also, `src/Templates/src/Microsoft.Maui.Templates.csproj:65` only packs the manifest when `GenerateCgManifest` is true:

```xml

```

The property defaults to false (`eng/CgManifest.targets:20`, `Microsoft.Maui.Templates.csproj:150`), and I only found examples/docs/target declarations, not a real pipeline setting it to true. So the manifest does not appear to be shipped in the template nupkg today.

That raises the design question: if the Component Governance scanner only needs this file on disk at build/scan time, and the build already regenerates it before the scan, should `src/Templates/src/cgmanifest.json` be `.gitignore`d and treated as a build artifact instead of checked in? The checked-in copy seems to drift permanently and creates confusing PR diffs.

## 5. Repo guidance is contradictory

Different repo guidance says different things:

- `.github/copilot-instructions.md:150-154`: `cgmanifest.json` is auto-generated and must not be committed.
- `.github/agents/maui-expert-reviewer.md:436`: never commit `cgmanifest.json`.
- `.github/instructions/templates.instructions.md:72-76`: never modify `cgmanifest.json`; it is regenerated during build.
- `docs/CgManifest.md:108`: says contributors can edit `cgmanifest.json` directly and manual entries are preserved.

History also shows manual commits: #32360 (`Update cgmanifest`) was authored by a human; #32361 appears to be the automated backport. This contradiction surfaced again in #35950, where a contributor reasonably hand-edited the manifest and review had to determine whether it was needed.

## Proposed fixes

1. Fix the SQLitePCLRaw mapping so the package actually referenced by the template is emitted. Options include:
- add a `SQLitePCLRawBundleESqlite3PackageVersion` property with the template's `3.0.3` value and keep the current mapping, or
- update the script/mapping/template version source so `SQLitePCLRaw.bundle_e_sqlite3` resolves consistently.
2. Remove or correct the false `docs/CgManifest.md:108` claim that manual entries are preserved.
3. Fix the `dotnet tool resotre` typo in `docs/CgManifest.md:18`.
4. Decide the intended model for `src/Templates/src/cgmanifest.json`:
- treat it as a generated build artifact and `.gitignore` it, or
- keep it checked in but add a CI/build verification gate that regenerates and fails on drift.
5. Reconcile `.github/*` agent/contributor instructions with `docs/CgManifest.md` so contributors get one consistent rule.

Related context: this was surfaced while reviewing #35950. Prior manual update example: #32360. This issue intentionally does not use closing keywords.

### Steps to Reproduce

1. From a clean `net11.0`-based checkout, inspect `eng/scripts/update-cgmanifest.ps1:60` and `eng/Versions.props:171`.
2. Confirm `src/Templates/src/templates/maui-mobile/MauiApp.1.csproj:86` references `SQLitePCLRaw.bundle_e_sqlite3`.
3. Back up `src/Templates/src/cgmanifest.json`.
4. Run `pwsh -NonInteractive -ExecutionPolicy Bypass -File eng/scripts/update-cgmanifest.ps1`.
5. Observe the warning for `SQLitePCLRaw.bundle_e_sqlite3` and the generated diff that deletes `SQLitePCLRaw.bundle_green` without adding `SQLitePCLRaw.bundle_e_sqlite3`.
6. Restore the backed-up manifest.

Expected outcome: every NuGet package that the templates require and that CG cannot otherwise discover is represented in the generated manifest, and the committed/generated state is either intentionally absent or kept in sync.

Actual outcome: `SQLitePCLRaw.bundle_e_sqlite3` is omitted by generation, the checked-in manifest is stale, and repo docs/instructions conflict on whether direct manifest edits are allowed.

### Link to public reproduction project repository

N/A

### Version with bug

11.0.0-preview.6 / `net11.0` branch infrastructure

### Is this a regression from previous behavior?

Not sure, did not test other versions

### Last version that worked well

Unknown/Other

### Affected platforms

Other (engineering infrastructure / Component Governance)

### Affected platform versions

N/A

### Did you find any workaround?

Manual restoration/edits are possible, but the current generator will remove entries it does not know how to recreate. A reliable workaround is to fix the mapping/version source or stop checking in the generated file.

### Relevant log output

```shell
Reading versions from: .../eng/Versions.props
Reading existing cgmanifest.json: .../src/Templates/src/cgmanifest.json
Setting up CommunityToolkit.Maui entries...
WARNING: Could not find version for SQLitePCLRaw.bundle_e_sqlite3 (property: SQLitePCLRawBundleESqlite3PackageVersion)
Updated cgmanifest.json saved to: .../src/Templates/src/cgmanifest.json
Successfully added 18 package registrations to cgmanifest.json
```

Contributor guide

Open the contributing guide

Research direction

Start with eng/scripts/update-cgmanifest.ps1, eng/Versions.props, and src/Templates/src/templates/maui-mobile/MauiApp.1.csproj, then run the documented PowerShell generator to reproduce the missing SQLitePCLRaw registration. Review src/Templates/src/cgmanifest.json, eng/CgManifest.targets, the template project, docs/CgManifest.md, and the referenced .github guidance. Done means the dependency coverage, generated-file policy, and contributor instructions agree and the documented regeneration outcome is correct.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, powershell
Domain
build-system, documentation, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.