Skip to content

Commit 8a433b7

Browse files
adamintCopilot
andcommitted
Fix Aspire CLI npm signing scope (#17770)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a22271a commit 8a433b7

2 files changed

Lines changed: 38 additions & 3 deletions

File tree

eng/Signing.props

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,14 @@
6969

7070
<!--
7171
npm packages are tarballs, but only the Aspire CLI npm tarballs should get
72-
detached signatures. Scope both the .tgz rule and the nested JavaScript
73-
launcher override to the npm package ItemsToSign collision id so the global
74-
.tgz/.js defaults remain unchanged for unrelated artifacts.
72+
detached signatures. Scope these rules to the npm package ItemsToSign
73+
collision id so the global .tgz/.js/native-executable defaults remain
74+
unchanged for unrelated artifacts.
7575
-->
7676
<FileExtensionSignInfo Include=".tgz" CertificateName="LinuxSign500180PGP" CollisionPriorityId="AspireCliNpmPackage" />
7777
<FileSignInfo Include="aspire.js" CertificateName="MicrosoftDotNet500" CollisionPriorityId="AspireCliNpmPackage" />
78+
<FileSignInfo Include="aspire.exe" CertificateName="None" CollisionPriorityId="AspireCliNpmPackage" />
79+
<FileSignInfo Include="aspire" CertificateName="None" CollisionPriorityId="AspireCliNpmPackage" />
7880
</ItemGroup>
7981

8082
<ItemGroup>

tests/Infrastructure.Tests/Pipelines/NpmCliPackageTests.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Xml.Linq;
45
using Xunit;
56

67
namespace Infrastructure.Tests;
@@ -200,6 +201,23 @@ public async Task NpmInstallValidationJobsUseExplicitJobsSharedStepsTemplateAndC
200201
Assert.Contains("$(NPM_VALIDATION_SUMMARY_OSX_ARTIFACT)", releasePipeline);
201202
}
202203

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+
203221
[Fact]
204222
public async Task ReleasePipelinePreflightsScheduledNpmPackagesBeforePublishing()
205223
{
@@ -265,6 +283,21 @@ private static int CountOccurrences(string value, string substring)
265283
return count;
266284
}
267285

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+
268301
private static string FindRepoRoot()
269302
{
270303
string? current = AppContext.BaseDirectory;

0 commit comments

Comments
 (0)