diff --git a/PowerShell.Common.props b/PowerShell.Common.props index cf5c11c9ed..99b5341804 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -137,8 +137,6 @@ net7.0 10.0 - true - true true true @@ -171,9 +169,17 @@ + true + true true + + + true + full + + true @@ -193,6 +199,8 @@ + true + true portable diff --git a/build.psm1 b/build.psm1 index e0c067aaa8..4a92627eab 100644 --- a/build.psm1 +++ b/build.psm1 @@ -319,7 +319,7 @@ function Start-PSBuild { "win7-x86")] [string]$Runtime, - [ValidateSet('Debug', 'Release', 'CodeCoverage', '')] # We might need "Checked" as well + [ValidateSet('Debug', 'Release', 'CodeCoverage', 'StaticAnalysis', '')] # We might need "Checked" as well [string]$Configuration, [ValidatePattern("^v\d+\.\d+\.\d+(-\w+(\.\d{1,2})?)?$")] @@ -814,7 +814,7 @@ function Compress-TestContent { function New-PSOptions { [CmdletBinding()] param( - [ValidateSet("Debug", "Release", "CodeCoverage", '')] + [ValidateSet('Debug', 'Release', 'CodeCoverage', 'StaticAnalysis', '')] [string]$Configuration, [ValidateSet("net7.0")] @@ -2234,7 +2234,7 @@ function Start-DevPowerShell { [string[]]$ArgumentList = @(), [switch]$LoadProfile, [Parameter(ParameterSetName='ConfigurationParamSet')] - [ValidateSet("Debug", "Release", "CodeCoverage", '')] # should match New-PSOptions -Configuration values + [ValidateSet('Debug', 'Release', 'CodeCoverage', 'StaticAnalysis', '')] # should match New-PSOptions -Configuration values [string]$Configuration, [Parameter(ParameterSetName='BinDirParamSet')] [string]$BinDir, diff --git a/tools/releaseBuild/azureDevOps/compliance.yml b/tools/releaseBuild/azureDevOps/compliance.yml index 0b713cb0ae..1993523721 100644 --- a/tools/releaseBuild/azureDevOps/compliance.yml +++ b/tools/releaseBuild/azureDevOps/compliance.yml @@ -39,6 +39,13 @@ stages: - template: templates/compliance/compliance.yml parameters: parentJobs: [] + - stage: APIScan + displayName: 'ApiScan' + dependsOn: [] + jobs: + - template: templates/compliance/apiscan.yml + parameters: + parentJobs: [] - stage: notice displayName: Generate Notice File dependsOn: [] diff --git a/tools/releaseBuild/azureDevOps/templates/compliance.yml b/tools/releaseBuild/azureDevOps/templates/compliance.yml index 0c4a162bb1..0a416389bf 100644 --- a/tools/releaseBuild/azureDevOps/templates/compliance.yml +++ b/tools/releaseBuild/azureDevOps/templates/compliance.yml @@ -9,9 +9,6 @@ jobs: - name: NugetSecurityAnalysisWarningLevel value: none - # Defines the variables APIScanClient, APIScanTenant and APIScanSecret - - group: PS-PS-APIScan - displayName: Compliance dependsOn: ${{ parameters.parentJobs }} @@ -20,9 +17,6 @@ jobs: demands: - ImageOverride -equals PSMMS2019-Secure - # APIScan can take a long time - timeoutInMinutes: 180 - steps: - checkout: self clean: true @@ -93,18 +87,6 @@ jobs: # PreFASt is not applicable - - task: securedevelopmentteam.vss-secure-development-tools.build-task-apiscan.APIScan@2 - displayName: 'Run APIScan' - inputs: - softwareFolder: '$(CompliancePath)' - softwareName: PowerShell - softwareVersionNum: '$(ReleaseTagVar)' - isLargeApp: false - preserveTempFiles: true - env: - AzureServicesAuthConnectionString: RunAs=App;AppId=$(APIScanClient);TenantId=$(APIScanTenant);AppKey=$(APIScanSecret) - continueOnError: true - - task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@2 displayName: 'Publish Security Analysis Logs to Build Artifacts' continueOnError: true @@ -129,7 +111,7 @@ jobs: displayName: 'Create Security Analysis Report' inputs: TsvFile: false - APIScan: true + APIScan: false BinSkim: true CredScan: true PoliCheck: true diff --git a/tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml b/tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml new file mode 100644 index 0000000000..0aa6c498f4 --- /dev/null +++ b/tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml @@ -0,0 +1,112 @@ +jobs: + - job: APIScan + variables: + - name: runCodesignValidationInjection + value : false + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: ReleaseTagVar + value: fromBranch + # Defines the variables APIScanClient, APIScanTenant and APIScanSecret + - group: PS-PS-APIScan + # PAT permissions NOTE: Declare a SymbolServerPAT variable in this group with a 'microsoft' organizanization scoped PAT with 'Symbols' Read permission. + # A PAT in the wrong org will give a single Error 203. No PAT will give a single Error 401, and individual pdbs may be missing even if permissions are correct. + - group: symbols + + pool: + name: PowerShell1ES + demands: + - ImageOverride -equals PSMMS2019-Secure + + # APIScan can take a long time + timeoutInMinutes: 180 + + steps: + - template: ../SetVersionVariables.yml + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: yes + UseJson: no + + - pwsh: | + Import-Module .\build.psm1 -force + Start-PSBootstrap + workingDirectory: '$(Build.SourcesDirectory)' + retryCountOnTaskFailure: 2 + displayName: 'Bootstrap' + + - pwsh: | + Import-Module .\build.psm1 -force + Find-DotNet + dotnet tool install dotnet-symbol --tool-path $(Agent.ToolsDirectory)\tools\dotnet-symbol + $symbolToolPath = Get-ChildItem -Path $(Agent.ToolsDirectory)\tools\dotnet-symbol\dotnet-symbol.exe | Select-Object -First 1 -ExpandProperty FullName + Write-Host "##vso[task.setvariable variable=symbolToolPath]$symbolToolPath" + displayName: Install dotnet-symbol + retryCountOnTaskFailure: 2 + + - pwsh: | + Import-Module .\build.psm1 -force + Find-DotNet + Start-PSBuild -Configuration StaticAnalysis -PSModuleRestore -Clean + + $OutputFolder = Split-Path (Get-PSOutput) + Write-Host "##vso[task.setvariable variable=BinDir]$OutputFolder" + workingDirectory: '$(Build.SourcesDirectory)' + displayName: 'Build PowerShell Source' + + - pwsh: | + Get-ChildItem -Path env: + displayName: Capture Environment + condition: succeededOrFailed() + + # Explicitly download symbols for the drop since the SDL image doesn't have http://SymWeb access and APIScan cannot handle https yet. + - pwsh: | + Import-Module .\build.psm1 -force + Find-DotNet + $pat = '$(SymbolServerPAT)' + if ($pat -like '*PAT*' -or $pat -eq '') + { + throw 'No PAT defined' + } + $url = 'https://microsoft.artifacts.visualstudio.com/defaultcollection/_apis/symbol/symsrv' + $(symbolToolPath) --authenticated-server-path $(SymbolServerPAT) $url --symbols -d "$env:BinDir\*" --recurse-subdirectories + displayName: 'Download Symbols for binaries' + retryCountOnTaskFailure: 2 + workingDirectory: '$(Build.SourcesDirectory)' + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-apiscan.APIScan@2 + displayName: 'Run APIScan' + inputs: + softwareFolder: '$(BinDir)' + softwareName: PowerShell + softwareVersionNum: '$(ReleaseTagVar)' + isLargeApp: false + preserveTempFiles: false + verbosityLevel: standard + # write a status update every 5 minutes. Default is 1 minute + statusUpdateInterval: '00:05:00' + env: + AzureServicesAuthConnectionString: RunAs=App;AppId=$(APIScanClient);TenantId=$(APIScanTenant);AppKey=$(APIScanSecret) + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-report.SdtReport@2 + continueOnError: true + displayName: 'Guardian Export' + inputs: + GdnExportVstsConsole: true + GdnExportSarifFile: true + GdnExportHtmlFile: true + GdnExportAllTools: false + GdnExportGdnToolApiScan: true + #this didn't do anything GdnExportCustomLogsFolder: '$(Build.ArtifactStagingDirectory)/Guardian' + + - pwsh: | + Get-ChildItem -Path env: + displayName: Capture Environment + condition: succeededOrFailed() + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@3 + displayName: 'Publish Guardian Artifacts' + inputs: + AllTools: false + APIScan: true + ArtifactName: APIScan