Skip to content

Commit fdef5bb

Browse files
lucygramleyCopilot
andauthored
Fix NTVS insertion SignCheck: resolve makecat.exe from the Windows SDK (#2556)
* Fix content catalog signing: resolve makecat.exe from Windows SDK The GenerateContentCatalog target invoked a bare `makecat.exe`, which is not on PATH on the official build agents. It failed with exit code 9009 and, because the Exec used IgnoreExitCode=true, the .cat was silently never produced, signed, or bundled into the VSIX. Insertions therefore shipped 33 unsigned .js/.xml template files and were rejected by the VS insertion SignCheck. Resolve makecat.exe explicitly from the Windows 10 SDK (ToolLocationHelper with a registry fallback) and fail the build loudly if the catalog cannot be produced, so an unsigned payload can never ship silently again. Bug: 2982241 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2f944511-9280-4ed2-aa0c-045bd63b66f2 * Exclude zero-byte files from content catalog makecat.exe cannot hash a 0-byte file: it aborts with 'NOT processed: calculating the indirect data' / 'Errors found in parsing the CDF file' and produces no catalog. EmptyJs.js is a 0-byte placeholder template, so it broke catalog generation once the makecat.exe exit code was no longer ignored. Filter zero-byte files out of the catalog source list via a RoslynCodeTaskFactory inline task before writing the CDF. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2f944511-9280-4ed2-aa0c-045bd63b66f2 * Fix catalog source paths and VSIX embedding hook Two bugs prevented the content catalog from actually protecting the template files, so the build went green while still shipping 32 unsigned .js/.xml files: 1. _CatalogSourceDir used '..\Nodejs\...' / '..\..\Extras' / '..\TestAdapter\...', which resolve one level too high from Nodejs\Product\ and do not exist, so zero files were collected and makecat never ran (guarded on count > 0). 2. IncludeCatalogInVsix hooked BeforeTargets=CreateVsixContainer, but CreateVsixContainer depends on GetVsixSourceItems, which had already enumerated the package contents - so the signed .cat was never added to the VSIX. Hook BeforeTargets=GetVsixSourceItems instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2f944511-9280-4ed2-aa0c-045bd63b66f2 * Give each catalog member a unique tag to prevent hash drop-out makecat keeps only one entry per member name, so template files that share a basename across directories (the five UnitTest.js item templates and the six roletemplatedata.xml cloud-role templates) collided under a single '<hash>UnitTest.js' / '<hash>roletemplatedata.xml' tag - only the first was cataloged and the other 9 shipped unsigned. Assign a unique CatTag (index_filename) per file in the CDF. Verified locally: NodejsToolsVsix 26/26 and TestAdapterVsix 12/12 non-empty js/xml now covered. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2f944511-9280-4ed2-aa0c-045bd63b66f2 * Make EmptyJs.js template non-empty so it can be catalog-signed The 0-byte EmptyJs.js template cannot be hashed by makecat, leaving it uncovered by the content catalog and flagged by the VS Insertion Sign Check. Add a minimal newline so all 33 shipped template files are catalog-signed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2f944511-9280-4ed2-aa0c-045bd63b66f2 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 3f6316b commit fdef5bb

2 files changed

Lines changed: 82 additions & 15 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

Nodejs/Product/ProjectAfter.targets

Lines changed: 81 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,44 @@
11
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
22
<Import Project="$(BuildRoot)\Build\fileVersion.targets" />
3+
4+
<!--
5+
makecat.exe cannot hash a zero-byte file: it aborts with
6+
"NOT processed: calculating the indirect data" / "Errors found in parsing
7+
the CDF file" and produces no catalog at all. Empty placeholder templates
8+
(e.g. EmptyJs.js) carry no content to protect, so they must be filtered out
9+
of the catalog source list. This inline task returns only non-empty files.
10+
-->
11+
<UsingTask TaskName="SelectNonEmptyFiles" TaskFactory="RoslynCodeTaskFactory"
12+
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
13+
<ParameterGroup>
14+
<InputFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
15+
<NonEmptyFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="true" />
16+
</ParameterGroup>
17+
<Task>
18+
<Using Namespace="System.IO" />
19+
<Using Namespace="System.Collections.Generic" />
20+
<Code Type="Fragment" Language="cs"><![CDATA[
21+
var kept = new List<Microsoft.Build.Framework.ITaskItem>();
22+
int index = 0;
23+
foreach (var item in InputFiles)
24+
{
25+
var p = item.GetMetadata("FullPath");
26+
if (File.Exists(p) && new FileInfo(p).Length > 0)
27+
{
28+
// Assign a unique catalog member tag. makecat keeps only one entry
29+
// per member name, so files sharing a basename (e.g. the several
30+
// UnitTest.js / roletemplatedata.xml templates) would otherwise
31+
// collide and all but one would be dropped from the catalog.
32+
item.SetMetadata("CatTag", index + "_" + Path.GetFileName(p));
33+
kept.Add(item);
34+
index++;
35+
}
36+
}
37+
NonEmptyFiles = kept.ToArray();
38+
]]></Code>
39+
</Task>
40+
</UsingTask>
41+
342
<Target Name="GatherLocalizedOutputsForSigning" Condition="'$(LocalizationEnabled)' == 'true'">
443
<ItemGroup>
544
<FilesToSign Include="$(OutDir)\localize\**\$(AssemblyName).resources.dll">
@@ -29,18 +68,23 @@
2968
<ItemGroup>
3069
<!-- NodejsToolsVsix: project templates, item templates, and extras -->
3170
<_CatalogSourceDir Condition="'$(MSBuildProjectName)' == 'NodejsToolsVsix'"
32-
Include="$(MSBuildThisFileDirectory)..\Nodejs\ProjectTemplates;$(MSBuildThisFileDirectory)..\Nodejs\Templates\Files;$(MSBuildThisFileDirectory)..\..\Extras" />
71+
Include="$(MSBuildThisFileDirectory)Nodejs\ProjectTemplates;$(MSBuildThisFileDirectory)Nodejs\Templates\Files;$(MSBuildThisFileDirectory)..\Extras" />
3372
<!-- TestAdapterVsix: test framework scripts -->
3473
<_CatalogSourceDir Condition="'$(MSBuildProjectName)' == 'TestAdapterVsix'"
35-
Include="$(MSBuildThisFileDirectory)..\TestAdapter\TestFrameworks" />
74+
Include="$(MSBuildThisFileDirectory)TestAdapter\TestFrameworks" />
3675
</ItemGroup>
3776

3877
<ItemGroup>
39-
<_CatSourceFile Include="%(_CatalogSourceDir.Identity)\**\*.js" />
40-
<_CatSourceFile Include="%(_CatalogSourceDir.Identity)\**\*.xml"
41-
Exclude="%(_CatalogSourceDir.Identity)\**\*.vstemplate" />
78+
<_CatSourceFileAll Include="%(_CatalogSourceDir.Identity)\**\*.js" />
79+
<_CatSourceFileAll Include="%(_CatalogSourceDir.Identity)\**\*.xml"
80+
Exclude="%(_CatalogSourceDir.Identity)\**\*.vstemplate" />
4281
</ItemGroup>
4382

83+
<!-- Drop zero-byte files (e.g. EmptyJs.js); makecat.exe rejects the whole CDF otherwise. -->
84+
<SelectNonEmptyFiles InputFiles="@(_CatSourceFileAll)">
85+
<Output TaskParameter="NonEmptyFiles" ItemName="_CatSourceFile" />
86+
</SelectNonEmptyFiles>
87+
4488
<!-- Write CDF (Catalog Definition File) -->
4589
<WriteLinesToFile File="$(_CdfFile)" Lines="[CatalogHeader]" Overwrite="true" />
4690
<WriteLinesToFile File="$(_CdfFile)" Lines="Name=$(_CatBaseName).cat" />
@@ -49,18 +93,35 @@
4993
<WriteLinesToFile File="$(_CdfFile)" Lines="HashAlgorithms=SHA256" />
5094
<WriteLinesToFile File="$(_CdfFile)" Lines="" />
5195
<WriteLinesToFile File="$(_CdfFile)" Lines="[CatalogFiles]" />
52-
<WriteLinesToFile File="$(_CdfFile)" Lines="@(_CatSourceFile->'&lt;hash&gt;%(Filename)%(Extension)=%(FullPath)')" />
96+
<WriteLinesToFile File="$(_CdfFile)" Lines="@(_CatSourceFile->'&lt;hash&gt;%(CatTag)=%(FullPath)')" />
5397

5498
<MakeDir Directories="$(OutDir)" />
55-
<Exec Command="makecat.exe &quot;$(_CdfFile)&quot;"
99+
100+
<!--
101+
Resolve makecat.exe from the Windows 10 SDK. It is NOT on PATH on the official
102+
build agents, so a bare 'makecat.exe' invocation fails with exit code 9009 and,
103+
because the call previously ignored the exit code, the .cat was silently never
104+
produced or signed - shipping an unsigned payload that fails the VS insertion
105+
SignCheck (33 unsigned .js/.xml files). Resolve the SDK location explicitly.
106+
-->
107+
<PropertyGroup>
108+
<_WindowsSdkDir>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPlatformSDKLocation('Windows', '10.0'))</_WindowsSdkDir>
109+
<_WindowsSdkDir Condition="'$(_WindowsSdkDir)' == ''">$(registry:HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots@KitsRoot10)</_WindowsSdkDir>
110+
<_WindowsSdkDir Condition="'$(_WindowsSdkDir)' == ''">$(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots@KitsRoot10)</_WindowsSdkDir>
111+
<_WindowsSdkVersion>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0'))</_WindowsSdkVersion>
112+
<_MakeCatExe>$(_WindowsSdkDir)bin\$(_WindowsSdkVersion)\x64\makecat.exe</_MakeCatExe>
113+
<_MakeCatExe Condition="!Exists('$(_MakeCatExe)')">$(_WindowsSdkDir)bin\$(_WindowsSdkVersion)\x86\makecat.exe</_MakeCatExe>
114+
</PropertyGroup>
115+
116+
<Error Text="makecat.exe was not found under the Windows 10 SDK (resolved dir '$(_WindowsSdkDir)', version '$(_WindowsSdkVersion)'). The content catalog required for VS signing compliance cannot be generated."
117+
Condition="!Exists('$(_MakeCatExe)') AND @(_CatSourceFile->Count()) > 0" />
118+
119+
<Exec Command="&quot;$(_MakeCatExe)&quot; &quot;$(_CdfFile)&quot;"
56120
StandardOutputImportance="High"
57-
IgnoreExitCode="true"
58-
Condition="@(_CatSourceFile->Count()) > 0">
59-
<Output TaskParameter="ExitCode" PropertyName="_MakecatExitCode" />
60-
</Exec>
121+
Condition="@(_CatSourceFile->Count()) > 0" />
61122

62-
<Warning Text="makecat.exe not found or failed (exit code $(_MakecatExitCode)). Catalog file not generated. This is expected for local builds without the Windows SDK."
63-
Condition="'$(_MakecatExitCode)' != '0' AND @(_CatSourceFile->Count()) > 0" />
123+
<Error Text="Content catalog '$(_CatFile)' was not produced by makecat.exe. The VSIX would ship without a signed catalog and fail the insertion SignCheck."
124+
Condition="!Exists('$(_CatFile)') AND @(_CatSourceFile->Count()) > 0" />
64125

65126
<!-- Sign the .cat file -->
66127
<ItemGroup Condition="Exists('$(_CatFile)')">
@@ -72,10 +133,15 @@
72133

73134
<!--
74135
Include the signed .cat file in the VSIX container.
75-
Runs after MicroBuild signing so the .cat is already signed.
136+
Must run BEFORE GetVsixSourceItems (which enumerates @(VSIXSourceItem)
137+
into the package) - hooking BeforeTargets=CreateVsixContainer is too late,
138+
because CreateVsixContainer depends on GetVsixSourceItems, so the item is
139+
added after the package contents are already gathered and never ships.
140+
GenerateContentCatalog (AfterTargets=Build) + MicroBuild signing both run
141+
before GetVsixSourceItems, so the .cat is already signed by this point.
76142
-->
77143
<Target Name="IncludeCatalogInVsix"
78-
BeforeTargets="CreateVsixContainer"
144+
BeforeTargets="GetVsixSourceItems"
79145
Condition="'$(CreateVsixContainer)' == 'true' AND '$(SignType)' != ''"
80146
DependsOnTargets="GenerateContentCatalog">
81147
<PropertyGroup>

0 commit comments

Comments
 (0)