Reference configs

dotnet/runtime: an MSBuild tree checked as XML

dotnet/runtime keeps most of its structure in XML, in 5,856 .csproj files and 607 .props and .targets files, and pins versions in global.json. This config reads them with XML and JSON path rules instead of regexes, next to the bundled dotnet ruleset. This config was written to test alint; dotnet/runtime doesn't use alint.

What alint found

The bundled GitHub Actions rules (alint 0.16.1, on the workflows as of 7 May 2026) flag 15 action references not pinned to a commit, 4 workflows that grant contents: write at the workflow level, such as backport.yml, and 2 that declare no permissions.

The config

Projects inherit settings from 361 Directory.Build files, eng/Subsets.props maps each build subset to its projects, and global.json and eng/Versions.props pin the SDK and tools. The config checks the SDK each project names and its nullable setting as XML, the pins in global.json, a Directory.Build.props in each area under src/ and the MIT header on C# sources. It extends the bundled dotnet, oss-baseline, ci/github-actions and hygiene/no-tracked-artifacts rulesets.

.alint.yml
- id: dotnet-runtime-csproj-uses-known-sdk
  kind: xml_path_matches
  paths:
    include:
      - "src/coreclr/**/*.csproj"
      - "src/libraries/**/*.csproj"
      - "src/mono/**/*.csproj"
      - "src/tasks/**/*.csproj"
      - "src/tools/**/*.csproj"
    exclude:
      - "**/bin/**"
      - "**/obj/**"
      - "**/artifacts/**"
      - "**/external/**"
      - "**/ref/**"
  path: "$.Project['@Sdk']"
  matches: '^(Microsoft\.NET\.Sdk(\.\w+)?|Microsoft\.Build\.(NoTargets|Traversal))$'
  if_present: true
  level: warning

xml_path_matches reads the Sdk attribute on each project's root element, so a commented-out or nested element can't satisfy it.

.alint.yml
- id: dotnet-runtime-global-json-sdk-and-tools-coherent
  kind: cross_file_value_equals
  source:
    file: global.json
    extract: { json: "$.sdk.version" }
  targets:
    - file: global.json
      extract: { json: "$.tools.dotnet" }
  normalize: trim
  level: error

global.json names the .NET SDK twice, for the SDK and for the tools; the two have to agree. Three more rules pin the SDK, Arcade and Helix versions.

.alint.yml
- id: dotnet-runtime-areas-have-directory-build-props
  kind: for_each_dir
  select: "src/{coreclr,libraries,mono,installer,tasks,tools}"
  require:
    - kind: file_exists
      paths: "{path}/Directory.Build.props"
  level: error

Each area under src/ sets its shared MSBuild properties in a Directory.Build.props.

What stays outside alint

What MSBuild computes and what runs on Helix stay there:

  • the Azure Pipelines matrix, Helix test runs and the internal pipeline templates;
  • what MSBuild computes from the props files: packaging, analyzer and trimming targets;
  • the API compatibility checks, which compare binaries with a previous release, and their CompatibilitySuppressions.xml baselines;
  • C# style, which dotnet format checks.