Skip to content

Commit f1ab9f9

Browse files
authored
Merge branch 'microsoft:main' into native-perf-benchmarking
2 parents c17c4fb + 3bca04b commit f1ab9f9

49 files changed

Lines changed: 4477 additions & 87 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.ado/jobs/desktop.yml

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -325,17 +325,9 @@ jobs:
325325

326326
- template: ../templates/stop-packagers.yml
327327

328-
- task: BinSkim@4
329-
displayName: Run Binskim Analysis
328+
- script: node .ado/scripts/build.js --binskim --platform ${{ matrix.BuildPlatform }} --configuration ${{ matrix.BuildConfiguration }} --target desktop
329+
displayName: Run BinSkim Analysis
330330
condition: eq('${{ matrix.BuildConfiguration }}', 'Release')
331-
inputs:
332-
InputType: 'Basic'
333-
Function: 'analyze'
334-
TargetPattern: 'guardianGlob'
335-
AnalyzeTargetGlob: '$(Build.SourcesDirectory)\vnext\target\${{ matrix.BuildPlatform }}\${{ matrix.BuildConfiguration }}\React.Windows.Desktop.DLL\react-native-win32.dll'
336-
AnalyzeVerbose: true
337-
toolVersion: 'Latest'
338-
continueOnError: true
339331

340332
- template: ../templates/publish-build-artifacts.yml
341333
parameters:

.ado/jobs/universal.yml

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -177,16 +177,9 @@
177177
targetPath: $(Build.SourcesDirectory)/vnext/target/${{ matrix.BuildPlatform }}/${{ matrix.BuildConfiguration }}
178178
artifactName: ReactWindows.${{ matrix.BuildPlatform }}.${{ matrix.BuildConfiguration }}
179179

180-
- task: BinSkim@4
181-
displayName: Run Binskim Analysis
180+
- script: node .ado/scripts/build.js --binskim --platform ${{ matrix.BuildPlatform }} --configuration ${{ matrix.BuildConfiguration }} --target universal
181+
displayName: Run BinSkim Analysis
182182
condition: and(succeeded(), eq('${{ matrix.BuildConfiguration }}', 'Release'), ne('${{ matrix.BuildPlatform }}', 'ARM64'))
183-
inputs:
184-
InputType: 'Basic'
185-
Function: 'analyze'
186-
TargetPattern: 'guardianGlob'
187-
AnalyzeTargetGlob: '$(Build.SourcesDirectory)\vnext\target\${{ matrix.BuildPlatform }}\${{ matrix.BuildConfiguration }}\Microsoft.ReactNative\Microsoft.ReactNative.dll'
188-
AnalyzeVerbose: true
189-
toolVersion: 'LatestPreRelease'
190183

191184
- template: ../templates/discover-google-test-adapter.yml
192185

.ado/release.yml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
# It releases npm packages to npmjs.com and NuGet packages to the public
44
# ms/react-native and ms/react-native-public ADO feeds and to nuget.org.
55
#
6-
# The triggers are overridden by the ADO pipeline UI definition.
6+
# The pipeline completion trigger is defined below in the pipeline resource.
7+
# Do NOT add a build completion trigger in the ADO UI — UI triggers override
8+
# YAML triggers and cause the pipeline to always run against the default branch
9+
# with incorrect metadata (wrong commit message and branch).
710
#
811

912
name: RNW NuGet Release $(Date:yyyyMMdd).$(Rev:r)
@@ -16,7 +19,13 @@ resources:
1619
- pipeline: 'Publish'
1720
project: 'ReactNative'
1821
source: 'Publish'
19-
trigger: none
22+
trigger:
23+
branches:
24+
include:
25+
- main
26+
- refs/heads/main
27+
- '*-stable'
28+
- 'refs/heads/*-stable'
2029
repositories:
2130
- repository: 1ESPipelineTemplates
2231
type: git

.ado/scripts/build.js

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
// .ado/scripts/build.js
2+
// BinSkim security validation for React Native Windows.
3+
//
4+
// Can be run locally or in the Azure DevOps pipeline.
5+
// Usage: node .ado/scripts/build.js --binskim [--platform x64] [--configuration Release] [--target desktop|universal]
6+
7+
import { execSync } from "node:child_process";
8+
import fs from "node:fs";
9+
import path from "node:path";
10+
import { parseArgs } from "node:util";
11+
import { fileURLToPath } from "node:url";
12+
13+
const __filename = fileURLToPath(import.meta.url);
14+
const __dirname = path.dirname(__filename);
15+
const sourcesPath = path.resolve(__dirname, "..", "..");
16+
17+
const binskimPackageName = "Microsoft.CodeAnalysis.BinSkim";
18+
const binskimVersion = "4.4.9";
19+
const binskimNuGetSource = "https://api.nuget.org/v3/index.json";
20+
21+
const options = {
22+
help: { type: "boolean", default: false },
23+
binskim: { type: "boolean", default: false },
24+
platform: { type: "string", default: "x64" },
25+
configuration: { type: "string", default: "Release" },
26+
target: { type: "string", default: "" }, // "desktop", "universal", or "" for both
27+
};
28+
29+
const args = parseArgs({ options, allowPositionals: false }).values;
30+
if (args.help) { printHelp(); process.exit(0); }
31+
32+
main();
33+
34+
function main() {
35+
if (!args.binskim) {
36+
console.log("No action specified. Use --binskim to run BinSkim analysis.");
37+
console.log("Run with --help for usage details.");
38+
return;
39+
}
40+
41+
const toolsPath = path.join(sourcesPath, "tools");
42+
const targetRoot = path.join(sourcesPath, "vnext", "target");
43+
const plat = args.platform;
44+
const config = args.configuration;
45+
46+
// Collect binaries based on --target flag.
47+
const candidates = [];
48+
if (!args.target || args.target === "desktop") {
49+
candidates.push(
50+
path.join(targetRoot, plat, config, "React.Windows.Desktop.DLL", "react-native-win32.dll")
51+
);
52+
}
53+
if (!args.target || args.target === "universal") {
54+
candidates.push(
55+
path.join(targetRoot, plat, config, "Microsoft.ReactNative", "Microsoft.ReactNative.dll")
56+
);
57+
}
58+
59+
runBinSkim({ toolsPath, candidates });
60+
}
61+
62+
function printHelp() {
63+
console.log(`
64+
Usage: node build.js --binskim [options]
65+
66+
Options:
67+
--binskim Run BinSkim security analysis on shipped DLLs
68+
--platform <arch> Build platform (default: x64)
69+
--configuration <cfg> Build configuration (default: Release)
70+
--target <type> Target to scan: desktop, universal, or omit for both
71+
--help Show this help message
72+
`);
73+
}
74+
75+
function ensureDir(dirPath) {
76+
if (!fs.existsSync(dirPath)) {
77+
fs.mkdirSync(dirPath, { recursive: true });
78+
}
79+
}
80+
81+
function ensureNuGet(toolsPath) {
82+
// Check if nuget.exe is already in the tools directory.
83+
const localNuGet = path.join(toolsPath, "nuget.exe");
84+
if (fs.existsSync(localNuGet)) {
85+
return localNuGet;
86+
}
87+
88+
// Check if nuget.exe is in PATH.
89+
try {
90+
const result = execSync("where nuget.exe", { encoding: "utf8" }).trim();
91+
if (result) {
92+
const firstLine = result.split(/\r?\n/)[0];
93+
console.log(`Found nuget.exe in PATH: ${firstLine}`);
94+
return firstLine;
95+
}
96+
} catch {
97+
// Not in PATH, download it.
98+
}
99+
100+
// Download nuget.exe from the official distribution.
101+
ensureDir(toolsPath);
102+
console.log(`Downloading nuget.exe to: ${localNuGet}`);
103+
execSync(
104+
`powershell.exe -NoLogo -NoProfile -Command ` +
105+
`"[Net.ServicePointManager]::SecurityProtocol = ` +
106+
`[Net.SecurityProtocolType]::Tls12; ` +
107+
`Invoke-WebRequest -Uri 'https://dist.nuget.org/win-x86-commandline/latest/nuget.exe' ` +
108+
`-OutFile '${localNuGet}' -UseBasicParsing"`,
109+
{ stdio: "inherit" },
110+
);
111+
112+
if (!fs.existsSync(localNuGet)) {
113+
throw new Error("Failed to download nuget.exe");
114+
}
115+
return localNuGet;
116+
}
117+
118+
function runBinSkim({ toolsPath, candidates }) {
119+
// Determine BinSkim.exe path within the NuGet package.
120+
const binskimDir = path.join(toolsPath, "binskim");
121+
const binskimPkgDir = path.join(
122+
binskimDir,
123+
`${binskimPackageName}.${binskimVersion}`,
124+
);
125+
126+
// Find BinSkim.exe under the package tools directory. The runtime folder
127+
// name varies by package version (e.g. netcoreapp3.1, net9.0).
128+
function findBinskimExe() {
129+
const toolsDir = path.join(binskimPkgDir, "tools");
130+
if (!fs.existsSync(toolsDir)) return null;
131+
for (const runtime of fs.readdirSync(toolsDir)) {
132+
const candidate = path.join(toolsDir, runtime, "win-x64", "BinSkim.exe");
133+
if (fs.existsSync(candidate)) return candidate;
134+
}
135+
return null;
136+
}
137+
138+
let binskimExe = findBinskimExe();
139+
140+
// Install BinSkim NuGet package if not already present.
141+
if (!binskimExe) {
142+
ensureDir(binskimDir);
143+
const nuget = ensureNuGet(toolsPath);
144+
console.log(
145+
`Installing ${binskimPackageName} ${binskimVersion} from ${binskimNuGetSource}...`,
146+
);
147+
execSync(
148+
`"${nuget}" install ${binskimPackageName}` +
149+
` -Version ${binskimVersion}` +
150+
` -Source "${binskimNuGetSource}"` +
151+
` -OutputDirectory "${binskimDir}"`,
152+
{ stdio: "inherit" },
153+
);
154+
binskimExe = findBinskimExe();
155+
if (!binskimExe) {
156+
throw new Error(
157+
`BinSkim.exe not found after install in: ${binskimPkgDir}`,
158+
);
159+
}
160+
}
161+
162+
// Filter to binaries that exist on disk.
163+
const binaries = candidates.filter((f) => fs.existsSync(f));
164+
165+
if (binaries.length === 0) {
166+
console.warn("BinSkim: No binaries found to scan. Skipping.");
167+
return;
168+
}
169+
170+
console.log(`\nRunning BinSkim ${binskimVersion} on ${binaries.length} binaries:`);
171+
for (const b of binaries) {
172+
console.log(` ${path.basename(b)}`);
173+
}
174+
175+
const fileArgs = binaries.map((b) => `"${b}"`).join(" ");
176+
try {
177+
execSync(
178+
`"${binskimExe}" analyze` +
179+
` --config default` +
180+
` --ignorePdbLoadError` +
181+
` --ignorePELoadErrors True` +
182+
` --hashes` +
183+
` --statistics` +
184+
` --disable-telemetry True` +
185+
` ${fileArgs}`,
186+
{ stdio: "inherit" },
187+
);
188+
console.log("\nBinSkim: All rules passed.");
189+
} catch (error) {
190+
console.error(
191+
`\nBinSkim failed with exit code: ${error.status || "unknown"}`,
192+
);
193+
process.exit(error.status || 1);
194+
}
195+
}

.gdn/.gdnsuppress

Lines changed: 0 additions & 12 deletions
This file was deleted.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ Directory.Build.local.targets
8989
*.userprefs
9090

9191
#Tooling
92+
tools/
9293
_ReSharper*/
9394
*.resharper
9495
[Tt]est[Rr]esult*

packages/@react-native-windows/automation-channel/CHANGELOG.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
{
22
"name": "@react-native-windows/automation-channel",
33
"entries": [
4+
{
5+
"date": "Thu, 12 Mar 2026 03:10:14 GMT",
6+
"version": "0.0.0-canary.1036",
7+
"tag": "@react-native-windows/automation-channel_v0.0.0-canary.1036",
8+
"comments": {
9+
"prerelease": [
10+
{
11+
"author": "beachball",
12+
"package": "@react-native-windows/automation-channel",
13+
"comment": "Bump react-native-windows to v0.0.0-canary.1036",
14+
"commit": "not available"
15+
}
16+
]
17+
}
18+
},
419
{
520
"date": "Wed, 11 Mar 2026 03:08:37 GMT",
621
"version": "0.0.0-canary.1035",

packages/@react-native-windows/automation-channel/CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
# Change Log - @react-native-windows/automation-channel
22

3-
<!-- This log was last generated on Wed, 11 Mar 2026 03:08:37 GMT and should not be manually modified. -->
3+
<!-- This log was last generated on Thu, 12 Mar 2026 03:10:14 GMT and should not be manually modified. -->
44

55
<!-- Start content -->
66

7+
## 0.0.0-canary.1036
8+
9+
Thu, 12 Mar 2026 03:10:14 GMT
10+
11+
### Changes
12+
13+
- Bump react-native-windows to v0.0.0-canary.1036
14+
715
## 0.0.0-canary.1035
816

917
Wed, 11 Mar 2026 03:08:37 GMT

packages/@react-native-windows/automation-channel/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@react-native-windows/automation-channel",
3-
"version": "0.0.0-canary.1035",
3+
"version": "0.0.0-canary.1036",
44
"license": "MIT",
55
"repository": {
66
"type": "git",
@@ -34,7 +34,7 @@
3434
"prettier": "2.8.8",
3535
"react": "19.2.0",
3636
"react-native": "0.83.0-nightly-20251104-502efe1cc",
37-
"react-native-windows": "^0.0.0-canary.1035",
37+
"react-native-windows": "^0.0.0-canary.1036",
3838
"typescript": "5.0.4"
3939
},
4040
"files": [

packages/@react-native-windows/automation-commands/CHANGELOG.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
{
22
"name": "@react-native-windows/automation-commands",
33
"entries": [
4+
{
5+
"date": "Thu, 12 Mar 2026 03:10:14 GMT",
6+
"version": "0.0.0-canary.1036",
7+
"tag": "@react-native-windows/automation-commands_v0.0.0-canary.1036",
8+
"comments": {
9+
"prerelease": [
10+
{
11+
"author": "beachball",
12+
"package": "@react-native-windows/automation-commands",
13+
"comment": "Bump @react-native-windows/automation-channel to v0.0.0-canary.1036",
14+
"commit": "not available"
15+
}
16+
]
17+
}
18+
},
419
{
520
"date": "Wed, 11 Mar 2026 03:08:37 GMT",
621
"version": "0.0.0-canary.1035",

0 commit comments

Comments
 (0)