tools: make-release.ps1: automate submissions to hardware dashboard

This commit is contained in:
Bill Zissimopoulos 2023-02-07 20:54:05 +00:00
parent 0ab4300738
commit 901a98e118
2 changed files with 385 additions and 6 deletions

View File

@ -68,6 +68,27 @@ function Get-ReleaseInfo ($Tag) {
} }
} }
function Get-HwapiCredentials {
$Credentials = (& "$ProjectRoot\tools\wincred.ps1" get "Hardware Dashboard API")
if ($Credentials) {
try { $Credentials = ConvertFrom-Json $Credentials[1] } catch {;}
}
if ($Credentials -and $Credentials.TenantId -and $Credentials.ClientId -and $Credentials.ClientId) {
return $Credentials
}
}
function Start-Sdcm {
Start-Job -ArgumentList $args -ScriptBlock {
$env:SDCM_CREDS_TENANTID = $using:HwapiCredentials.TenantId
$env:SDCM_CREDS_CLIENTID = $using:HwapiCredentials.ClientId
$env:SDCM_CREDS_KEY = $using:HwapiCredentials.Key
$env:SDCM_CREDS_URL = "https://manage.devcenter.microsoft.com"
$env:SDCM_CREDS_URLPREFIX = "v2.0/my"
& "$using:ProjectRoot\..\winfsp.sdcm\SurfaceDevCenterManager\bin\Debug\sdcm.exe" -creds envonly @args
} | Receive-Job -Wait -AutoRemoveJob
}
function Get-FileVersion ($FileName) { function Get-FileVersion ($FileName) {
return [System.Diagnostics.FileVersionInfo]::GetVersionInfo($FileName).FileVersion return [System.Diagnostics.FileVersionInfo]::GetVersionInfo($FileName).FileVersion
} }
@ -96,6 +117,12 @@ function Check-Prerequisites {
exit 1 exit 1
} }
# check scdm.exe
if (!(Get-Command "$ProjectRoot\..\winfsp.sdcm\SurfaceDevCenterManager\bin\Debug\sdcm.exe" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find sdcm.exe"
exit 1
}
# check gh.exe # check gh.exe
if (!(Get-Command "gh.exe" -ErrorAction SilentlyContinue)) { if (!(Get-Command "gh.exe" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find gh.exe" Write-Stderr "error: cannot find gh.exe"
@ -137,6 +164,17 @@ function Check-Prerequisites {
exit 1 exit 1
} }
# check hardware dashboard api credentials
$script:HwapiCredentials = Get-HwapiCredentials
if (!$script:HwapiCredentials) {
Write-Stderr "error: cannot get Hardware Dashboard API credentials"
Write-Stderr ' The expected format of the credentials is as follows:'
Write-Stderr ' TargetName: Hardware Dashboard API'
Write-Stderr ' UserName: Credentials'
Write-Stderr ' Password: {"TenantId":"TENANTID","ClientId":"CLIENTID","Key":"KEY"}'
exit 1
}
if ($State -contains $Name) { if ($State -contains $Name) {
if (!($State -contains "$Tag-$CommitCount-g$Commit")) { if (!($State -contains "$Tag-$CommitCount-g$Commit")) {
Write-Stderr "error: invalid state for tag $Tag" Write-Stderr "error: invalid state for tag $Tag"
@ -149,6 +187,12 @@ function Check-Prerequisites {
} }
function Check-Assets { function Check-Assets {
# check driver.cab
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\driver.cab" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find driver.cab"
exit 1
}
# check winfsp.msi # check winfsp.msi
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi" -ErrorAction SilentlyContinue)) { if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find winfsp*.msi" Write-Stderr "error: cannot find winfsp*.msi"
@ -192,8 +236,215 @@ function Build-AssetsPhase1 {
Write-Stdout @" Write-Stdout @"
Upload file driver.cab to Microsoft Partner Center for attestation signing. Assets have been built but are not properly signed.
When the file has been signed, download and extract to ~\Downloads\drivers Signable assets are ready for submission to the hardware dashboard.
"@
}
}
function Submit-AssetsToHwapi {
Task -ScriptBlock {
Check-Assets
$MsiFile = Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi"
$MsiName = Split-Path -Leaf $MsiFile
if ($MsiName -match "winfsp-(.+)\.msi") {
$Version = $matches[1]
}
if (!$Version) {
Write-Stderr "error: cannot determine version for winfsp.msi"
exit 1
}
$DocRequestedSignatures = @()
$Documentation = Invoke-WebRequest -Uri "https://raw.githubusercontent.com/MicrosoftDocs/windows-driver-docs/staging/windows-driver-docs-pr/dashboard/get-product-data.md"
$Documentation = $Documentation.Content
$List = $false
foreach ($Line in $Documentation -Split "`n") {
if ($Line -match "^### List of Operating System Codes") {
$List = $true
} elseif ($Line -match "^###") {
$List = $false
} elseif ($List -and $Line -cmatch "\| *(WINDOWS_v100_[^| ]+) *\|") {
$DocRequestedSignatures += $matches[1]
}
}
if ($DocRequestedSignatures.length -lt 32) {
Write-Stderr "error: cannot determine signatures to request"
Write-Stderr ' Does the document at the URL below still contain a "List of Operating System Codes":'
Write-Stderr " https://raw.githubusercontent.com/MicrosoftDocs/windows-driver-docs/staging/windows-driver-docs-pr/dashboard/get-product-data.md"
exit 1
}
# start with the base signatures and add any new ones found in the docs
$RequestedSignatures = @(
"WINDOWS_v100_TH2_FULL"
"WINDOWS_v100_X64_TH2_FULL"
"WINDOWS_v100_RS1_FULL"
"WINDOWS_v100_X64_RS1_FULL"
"WINDOWS_v100_RS2_FULL"
"WINDOWS_v100_X64_RS2_FULL"
"WINDOWS_v100_RS3_FULL"
"WINDOWS_v100_X64_RS3_FULL"
"WINDOWS_v100_ARM64_RS3_FULL"
"WINDOWS_v100_RS4_FULL"
"WINDOWS_v100_X64_RS4_FULL"
"WINDOWS_v100_ARM64_RS4_FULL"
"WINDOWS_v100_RS5_FULL"
"WINDOWS_v100_X64_RS5_FULL"
"WINDOWS_v100_ARM64_RS5_FULL"
"WINDOWS_v100_19H1_FULL"
"WINDOWS_v100_X64_19H1_FULL"
"WINDOWS_v100_ARM64_19H1_FULL"
"WINDOWS_v100_VB_FULL"
"WINDOWS_v100_X64_VB_FULL"
"WINDOWS_v100_ARM64_VB_FULL"
"WINDOWS_v100_X64_CO_FULL"
"WINDOWS_v100_ARM64_CO_FULL"
"WINDOWS_v100_X64_NI_FULL"
"WINDOWS_v100_ARM64_NI_FULL"
)
foreach ($Signature in $DocRequestedSignatures) {
if ($RequestedSignatures -contains $Signature) {
continue
}
if ($Signature.Contains("_SERVER_")) {
continue
}
if ($Signature -eq "WINDOWS_v100_TH1_FULL") {
continue
}
if ($Signature -eq "WINDOWS_v100_X64_TH1_FULL") {
continue
}
$RequestedSignatures += $Signature
Write-Stdout "New doc signature: $Signature"
}
$CreateProduct = @{
createType = "product"
createProduct = @{
productName = "winfsp-$Version"
testHarness = "attestation"
deviceType = "internalExternal"
requestedSignatures = $RequestedSignatures
# deviceMetaDataIds = $null
# firmwareVersion = "0"
# isTestSign = $false
# isFlightSign = $false
# markettingNames = $null
# selectedProductTypes = $null
# additionalAttributes = $null
}
}
$CreateSubmission = @{
createType = "submission"
createSubmission = @{
name = "winfsp-$Version"
type = "initial"
}
}
New-Item "$ProjectRoot\build\VStudio\build\Release\hwapi" -Type Directory -ErrorAction SilentlyContinue >$null
ConvertTo-Json $CreateProduct | Out-File -Encoding Ascii "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateProduct.json"
ConvertTo-Json $CreateSubmission | Out-File -Encoding Ascii "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateSubmission.json"
Start-Sdcm -create "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateProduct.json" | Tee-Object -Variable Output
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot create product on hardware dashboard"
exit 1
}
if (-not ([string]$Output -match "--- Product: (\d+)")) {
Write-Stderr "error: cannot get product id from hardware dashboard"
exit 1
}
$ProductId = $matches[1]
Start-Sdcm -create "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateSubmission.json" -productid $ProductId | Tee-Object -Variable Output
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot create submission on hardware dashboard"
exit 1
}
if (-not ([string]$Output -match "---- Submission: (\d+)")) {
Write-Stderr "error: cannot get submission id from hardware dashboard"
exit 1
}
$SubmissionId = $matches[1]
Set-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\ProductId" -Value $ProductId
Set-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\SubmissionId" -Value $SubmissionId
Write-Stdout @"
Product submission has been prepared on hardware dashboard.
"@
}
}
function Upload-AssetsToHwapi {
Task -ScriptBlock {
Check-Assets
$ProductId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\ProductId"
$SubmissionId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\SubmissionId"
Start-Sdcm -upload "$ProjectRoot\build\VStudio\build\Release\driver.cab" -productid $ProductId -submissionid $SubmissionId
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot upload driver.cab to hardware dashboard"
exit 1
}
Start-Sdcm -commit -productid $ProductId -submissionid $SubmissionId
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot commit submission to hardware dashboard"
exit 1
}
Write-Stdout @"
Signable assets have been uploaded to the hardware dashboard.
"@
}
}
function Download-AssetsFromHwapi {
Task -ScriptBlock {
Check-Assets
$ProductId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\ProductId"
$SubmissionId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\SubmissionId"
Remove-Item -Force "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -ErrorAction SilentlyContinue
Remove-Item -Recurse -Force "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers" -ErrorAction SilentlyContinue
Start-Sdcm -download "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -productid $ProductId -submissionid $SubmissionId
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot download signed drivers from hardware dashboard"
exit 1
}
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot download signed drivers from hardware dashboard"
exit 1
}
$ExpandError = ""
Expand-Archive "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -DestinationPath "$ProjectRoot\build\VStudio\build\Release\hwapi" -ErrorVariable ExpandError
if ($ExpandError) {
Write-Stderr "error: cannot expand signed drivers archive"
exit 1
}
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot expand signed drivers archive"
exit 1
}
Write-Stdout @"
Signable assets have been downloaded and can be used to complete the build.
"@ "@
} }
@ -204,16 +455,16 @@ function Build-AssetsPhase2 {
Check-Assets Check-Assets
# check signed drivers folder # check signed drivers folder
if (!(Test-Path ~\Downloads\drivers -ErrorAction SilentlyContinue)) { if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find ~\Downloads\drivers" Write-Stderr "error: cannot find hwapi\drivers"
exit 1 exit 1
} }
$SignedPackage = Resolve-Path ~\Downloads\drivers $SignedPackage = Resolve-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers"
$VerX64 = Get-FileVersion "$ProjectRoot\build\VStudio\build\Release\winfsp-x64.sys" $VerX64 = Get-FileVersion "$ProjectRoot\build\VStudio\build\Release\winfsp-x64.sys"
if ($VerX64 -ne (Get-FileVersion "$SignedPackage\x64\winfsp-x64.sys")) { if ($VerX64 -ne (Get-FileVersion "$SignedPackage\x64\winfsp-x64.sys")) {
Write-Stderr "error: incompatible versions in ~\Downloads\drivers" Write-Stderr "error: incompatible versions in hwapi\drivers"
exit 1 exit 1
} }
@ -375,8 +626,12 @@ Check-Prerequisites
# Workflow tasks # Workflow tasks
Build-AssetsPhase1 Build-AssetsPhase1
Submit-AssetsToHwapi
Upload-AssetsToHwapi
Download-AssetsFromHwapi
Build-AssetsPhase2 Build-AssetsPhase2
Make-GitHubRelease Make-GitHubRelease
Upload-Symbols Upload-Symbols
Make-NugetRelease Make-NugetRelease
Make-ChocoRelease Make-ChocoRelease
Write-Stdout "ALL COMPLETE"

124
tools/wincred.ps1 Normal file
View File

@ -0,0 +1,124 @@
Start-Job -ArgumentList $args -ScriptBlock {
param (
[ValidateSet("get", "set", "del")]
[string]$Command
)
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
namespace Win32
{
public class Api
{
public static String[] CredRead(
String TargetName)
{
String[] Result = null;
IntPtr CredentialPtr;
if (CredReadW(TargetName, 1/*CRED_TYPE_GENERIC*/, 0, out CredentialPtr))
{
CREDENTIALW Credential = Marshal.PtrToStructure<CREDENTIALW>(CredentialPtr);
Result = new String[2]{
Credential.UserName,
Marshal.PtrToStringUni(
Credential.CredentialBlob, (int)Credential.CredentialBlobSize / 2)
};
CredFree(CredentialPtr);
}
return Result;
}
public static Boolean CredWrite(
String TargetName,
String UserName,
String Password)
{
CREDENTIALW Credential = new CREDENTIALW{
Type = 1/*CRED_TYPE_GENERIC*/,
Persist = 2/*CRED_PERSIST_LOCAL_MACHINE*/,
TargetName = TargetName,
UserName = UserName,
CredentialBlobSize = (UInt32)Password.Length * 2,
CredentialBlob = Marshal.StringToCoTaskMemUni(Password),
};
Boolean Result = CredWriteW(ref Credential, 0);
Marshal.FreeCoTaskMem(Credential.CredentialBlob);
return Result;
}
public static Boolean CredDelete(
String TargetName)
{
return CredDeleteW(TargetName, 1/*CRED_TYPE_GENERIC*/, 0);
}
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
[return: MarshalAs(UnmanagedType.U1)]
private static extern Boolean CredReadW(
String TargetName,
UInt32 Type,
UInt32 Flags,
out IntPtr Credential);
[DllImport("advapi32.dll")]
private static extern void CredFree(
IntPtr Buffer);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
[return: MarshalAs(UnmanagedType.U1)]
private static extern Boolean CredWriteW(
ref CREDENTIALW Credential,
UInt32 Flags);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
[return: MarshalAs(UnmanagedType.U1)]
private static extern Boolean CredDeleteW(
String TargetName,
UInt32 Type,
UInt32 Flags);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct CREDENTIALW
{
public UInt32 Flags;
public UInt32 Type;
public String TargetName;
public String Comment;
public UInt64 LastWritten;
public UInt32 CredentialBlobSize;
public IntPtr CredentialBlob;
public UInt32 Persist;
public UInt32 AttributeCount;
public IntPtr Attributes;
public String TargetAlias;
public String UserName;
};
};
};
"@
function Get-WindowsCredential {
param (
[Parameter(Mandatory)][string]$TargetName
)
return [Win32.Api]::CredRead($TargetName)
}
function Set-WindowsCredential {
param (
[Parameter(Mandatory)][string]$TargetName,
[Parameter(Mandatory)][string]$UserName,
[Parameter(Mandatory)][string]$Password
)
return [Win32.Api]::CredWrite($TargetName, $UserName, $Password)
}
function Delete-WindowsCredential {
param (
[Parameter(Mandatory)][string]$TargetName
)
return [Win32.Api]::CredDelete($TargetName)
}
$Function = @{
"get" = "Get-WindowsCredential"
"set" = "Set-WindowsCredential"
"del" = "Delete-WindowsCredential"
}[$Command]
& $Function @args
} | Receive-Job -Wait -AutoRemoveJob