Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ below exist because ordinary review does not catch it.
| `PackagingConventionTests` | Every package ships its own README as `PackageReadmeFile`; `.targets` ship to both `build/` and `buildTransitive/`, reference a real `IDesignTimeServices` in their own assembly, and set `ForProvider` on satellites but not on core. Package validation is enabled and its baseline is the shipped version or the release before it, never older — the baseline is what `dotnet pack` diffs the public surface against (CP0002 on a removed member), and one left behind stops seeing API added since it. |
| `ClaudeMdConsistencyTests` | This file. Prose cannot be asserted, so it checks the falsifiable parts: cited paths and file names exist, annotation keys under a prefix this repo owns are declared somewhere, `Type.Member` references resolve, and the stated size of the Npgsql whitelist matches it. Those are what a rename rots silently — and the count claim had already gone stale by two. |
| `BuilderApiParityTests` | Every key in a satellite's annotation whitelist is reachable from a builder method. `SqlServer:DataCompression` sat whitelisted with no API for a full release; this catches that class of drift by invoking every builder extension and diffing the keys it sets. |
| `SecurityPolicyConsistencyTests` | SECURITY.md's supported-versions table names the minor being shipped, and its `< x.y` row meets it. The table is prose a version bump forgets — the sibling repository shipped 6.2.0 with the table still saying 6.1.x. |
| `SecurityPolicyConsistencyTests` | SECURITY.md's supported-versions table names the minor being shipped, and its `< x.y` row meets it; the support-horizon sentence names the EF Core major the core project's dependency floor targets. Both are prose a version bump forgets — the sibling repository shipped 6.2.0 with the table still saying 6.1.x. |
| `ReleaseWiringConventionTests` | The release path's silent failures: `release.yml` exists under the file name the nuget.org policy names, the publish job is gated on the `nuget` environment, only that job holds `id-token: write`, no job holds both `id-token: write` and `contents: write`, the tag is checked against `Directory.Build.props`, the SBOM tool is pinned in the manifest, and no second publishing path exists under `scripts/`. Rename the environment and nothing else in the build notices — the next tag fails to publish with an authentication error that never mentions the rename. |

**`test/consumer-smoke-test.sh`** is the only check that exercises *delivery* rather than code. Every
Expand Down
20 changes: 20 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,26 @@ remedy for those is to upgrade.
| 5.0.x | ✅ |
| < 5.0 | ❌ |

### For how long

There is no fixed end-of-support date. Each major of this package tracks one EF Core major — the
current line targets **EF Core 10** — and the intention is to keep it maintained for as long as
Microsoft supports that EF Core release (EF Core 10 is LTS, supported until November 2028), or
until a new major of this package supersedes it, whichever comes first. If that intention changes,
it is recorded here before anywhere else.

### If this project stops being maintained

This is a single-maintainer project, and that is the honest continuity risk. The signal would be
unambiguous: the repository archived, the packages marked deprecated on nuget.org, and a note here.
Published versions stay on nuget.org regardless (a package can be unlisted, not removed), the code
is MIT-licensed, and the release path needs nothing but this repository — forking is the intended
continuity mechanism, not a fallback.

Advisories are published as GitHub Security Advisories, which reach the GitHub Advisory Database
and from there `dotnet restore` (NuGetAudit): a consumer on an affected version sees a build
warning without subscribing to anything.

## Where this package sits

Useful context for judging impact, and for anyone doing supply-chain due diligence.
Expand Down
33 changes: 33 additions & 0 deletions test/EFCore.ComplexIndexes.Tests/SecurityPolicyConsistencyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,45 @@ public class SecurityPolicyConsistencyTests
private static readonly Regex UnsupportedRow =
new(@"^\|\s*<\s*(\d+)\.(\d+)\s*\|\s*❌\s*\|", RegexOptions.Multiline | RegexOptions.Compiled);

// "the current line targets **EF Core 10**" — the number the horizon statement is anchored to.
private static readonly Regex TargetsEfCore =
new(@"targets \*\*EF Core (\d+)\*\*", RegexOptions.Compiled);

private static Version PackageVersion =>
Version.Parse(XDocument.Load(RepositoryLayout.BuildProps)
.Descendants("Version")
.Single()
.Value);

/// <summary>
/// The support horizon is phrased against the EF Core major this line targets, and that number
/// lives in the core project's dependency floor. When the floor moves to EF Core 11 the sentence
/// has to move with it, or the policy promises support against a release the package no longer
/// targets.
/// </summary>
[TestMethod(DisplayName = "SECURITY.md's support horizon names the EF Core major the package targets")]
public void Support_horizon_names_the_targeted_ef_core_major()
{
var text = File.ReadAllText(SecurityPolicy);
var match = TargetsEfCore.Match(text);

Assert.IsTrue(
match.Success,
"SECURITY.md has no 'targets **EF Core N**' sentence in its support horizon — a consumer doing "
+ "due diligence needs to know which platform line the support intention is tied to.");

var core = RepositoryLayout.ShippingProjects.Single(p => !p.IsSatellite);
var reference = XDocument.Load(core.ProjectFile)
.Descendants("PackageReference")
.Single(r => r.Attribute("Include")?.Value == "Microsoft.EntityFrameworkCore.Abstractions");
var floor = Regex.Match(reference.Attribute("Version")!.Value, @"\d+").Value;

Assert.AreEqual(
floor, match.Groups[1].Value,
$"SECURITY.md says the current line targets EF Core {match.Groups[1].Value}, but the core "
+ $"project's EF Core floor is {floor}. Move the horizon statement with the floor.");
}

[TestMethod(DisplayName = "SECURITY.md's supported-versions table names the minor being shipped")]
public void Supported_versions_table_names_the_shipped_minor()
{
Expand Down
Loading