|
1 | 1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | 2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | 3 |
|
| 4 | +using System.Xml.Linq; |
4 | 5 | using Xunit; |
5 | 6 |
|
6 | 7 | namespace Infrastructure.Tests; |
@@ -200,6 +201,23 @@ public async Task NpmInstallValidationJobsUseExplicitJobsSharedStepsTemplateAndC |
200 | 201 | Assert.Contains("$(NPM_VALIDATION_SUMMARY_OSX_ARTIFACT)", releasePipeline); |
201 | 202 | } |
202 | 203 |
|
| 204 | + [Fact] |
| 205 | + public async Task NpmSigningScopeCoversNestedTarballPayloads() |
| 206 | + { |
| 207 | + var signingProps = XDocument.Parse(await ReadRepoFileAsync("eng/Signing.props")); |
| 208 | + |
| 209 | + AssertScopedSigningRule(signingProps, "FileExtensionSignInfo", ".tgz", "LinuxSign500180PGP"); |
| 210 | + AssertScopedSigningRule(signingProps, "FileSignInfo", "aspire.js", "MicrosoftDotNet500"); |
| 211 | + |
| 212 | + // The native npm packages are built from already-signed native archives. |
| 213 | + // The main Windows build should only produce the detached npm tarball |
| 214 | + // signature; it must still provide scoped rules for nested native |
| 215 | + // executables because Arcade resolves nested file certificates inside |
| 216 | + // the ItemsToSign collision scope. |
| 217 | + AssertScopedSigningRule(signingProps, "FileSignInfo", "aspire.exe", "None"); |
| 218 | + AssertScopedSigningRule(signingProps, "FileSignInfo", "aspire", "None"); |
| 219 | + } |
| 220 | + |
203 | 221 | [Fact] |
204 | 222 | public async Task ReleasePipelinePreflightsScheduledNpmPackagesBeforePublishing() |
205 | 223 | { |
@@ -265,6 +283,21 @@ private static int CountOccurrences(string value, string substring) |
265 | 283 | return count; |
266 | 284 | } |
267 | 285 |
|
| 286 | + private static void AssertScopedSigningRule(XDocument document, string elementName, string include, string certificateName) |
| 287 | + { |
| 288 | + var matchingRules = document |
| 289 | + .Descendants(elementName) |
| 290 | + .Where(element => |
| 291 | + (string?)element.Attribute("CollisionPriorityId") == "AspireCliNpmPackage" && |
| 292 | + ((string?)element.Attribute("Include") == include || (string?)element.Attribute("Update") == include) && |
| 293 | + (string?)element.Attribute("CertificateName") == certificateName) |
| 294 | + .ToArray(); |
| 295 | + |
| 296 | + Assert.True( |
| 297 | + matchingRules.Length == 1, |
| 298 | + $"Expected exactly one {elementName} for '{include}' using '{certificateName}' in the AspireCliNpmPackage signing scope, but found {matchingRules.Length}."); |
| 299 | + } |
| 300 | + |
268 | 301 | private static string FindRepoRoot() |
269 | 302 | { |
270 | 303 | string? current = AppContext.BaseDirectory; |
|
0 commit comments