diff --git a/.ci/ci.yml b/.ci/ci.yml index df3dda548..2a1576951 100644 --- a/.ci/ci.yml +++ b/.ci/ci.yml @@ -12,8 +12,12 @@ pr: #- master - development -variables: - - group: ESRP +resources: + repositories: + - repository: ComplianceRepo + type: github + endpoint: ComplianceGHRepo + name: PowerShell/compliance stages: - stage: Build @@ -22,7 +26,7 @@ stages: - job: BuildPkg displayName: Build Package pool: - vmImage: windows-2019 + vmImage: windows-latest steps: - powershell: | @@ -96,196 +100,14 @@ stages: $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" Import-Module -Name $modPath -Force - - $config = Get-PSPackageProjectConfiguration - - # Created files signing directory - $srcPath = "$($config.BuildOutputPath)\$($config.ModuleName)" - $createdSignSrcPath = "$($config.BuildOutputPath)\CreatedFiles" - if (! (Test-Path -Path $createdSignSrcPath)) { - $null = New-Item -Path $createdSignSrcPath -ItemType Directory -Verbose - } - Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PowerShellGet.psd1") -Dest $createdSignSrcPath -Force -Verbose - Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PSModule.psm1") -Dest $createdSignSrcPath -Force -Verbose - Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "DscResources") -Dest $createdSignSrcPath -Recurse -Force -Verbose - Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "Modules") -Dest $createdSignSrcPath -Recurse -Force -Verbose - - $net472Path = Join-Path -Path $createdSignSrcPath -ChildPath "net472" - if (! (Test-Path -Path $net472Path)) { - $null = New-Item -Path $net472Path -ItemType Directory -Verbose - } - Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "net472\PowerShellGet.*") -Dest $net472Path -Force -Verbose - - $netStandardPath = Join-Path -Path $createdSignSrcPath -ChildPath "netstandard2.0" - if (! (Test-Path -Path $netStandardPath)) { - $null = New-Item -Path $netStandardPath -ItemType Directory -Verbose - } - Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "netstandard2.0\PowerShellGet.*") -Dest $netStandardPath -Force -Verbose - - $signOutPath = "$($config.SignedOutputPath)\$($config.ModuleName)" - if (! (Test-Path -Path $signOutPath)) { - $null = New-Item -Path $signOutPath -ItemType Directory - } - - # Set signing src path variable - $vstsCommandString = "vso[task.setvariable variable=signSrcPath]${createdSignSrcPath}" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - - $outSignPath = "$($config.SignedOutputPath)\$($config.ModuleName)" - if (! (Test-Path -Path $outSignPath)) { - $null = New-Item -Path $outSignPath -ItemType Directory -Verbose - } - - # Set signing out path variable - $vstsCommandString = "vso[task.setvariable variable=signOutPath]${outSignPath}" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Set up for module created files code signing - condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - - - template: ./templates/sign.yml - parameters: - buildOutputPath: $(signSrcPath) - signOutputPath: $(signOutPath) - certificateId: "CP-230012" - pattern: '*.dll,*.psd1,*.psm1,*.ps1xml,*.mof' - - - pwsh: | - $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' - $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath - $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject - Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" - Import-Module -Name $modPath -Force - $config = Get-PSPackageProjectConfiguration - - $signOutPath = "$($config.SignedOutputPath)\$($config.ModuleName)" - if (! (Test-Path -Path $signOutPath)) { - $null = New-Item -Path $signOutPath -ItemType Directory - } - - # Third party files signing directory - $srcPath = "$($config.BuildOutputPath)\$($config.ModuleName)" - $thirdPartySignSrcPath = "$($config.BuildOutputPath)\ThirdParty" - if (! (Test-Path -Path $thirdPartySignSrcPath)) { - $null = New-Item -Path $thirdPartySignSrcPath -ItemType Directory -Verbose - } - - # Net472 directory - $net472Path = Join-Path -Path $thirdPartySignSrcPath -ChildPath "net472" - if (! (Test-Path -Path $net472Path)) { - $null = New-Item -Path $net472Path -ItemType Directory -Verbose - } - Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "net472") -Filter '*.dll' | Foreach-Object { - if ($_.Name -ne 'PowerShellGet.dll') { - $sig = Get-AuthenticodeSignature -FilePath $_.FullName - if ($sig.Status -ne 'Valid' -or $sig.SignerCertificate.Subject -notlike '*Microsoft*' -or $sig.SignerCertificate.Issuer -notlike '*Microsoft Code Signing PCA*') { - # Copy for third party signing - Copy-Item -Path $_.FullName -Dest $net472Path -Force -Verbose - } - } - } - - # NetStandard directory - $netStandardPath = Join-Path -Path $thirdPartySignSrcPath -ChildPath "netstandard2.0" - if (! (Test-Path -Path $netStandardPath)) { - $null = New-Item -Path $netStandardPath -ItemType Directory -Verbose - } - Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "netstandard2.0") -Filter '*.dll' | Foreach-Object { - if ($_.Name -ne 'PowerShellGet.dll') { - $sig = Get-AuthenticodeSignature -FilePath $_.FullName - if ($sig.Status -ne 'Valid' -or $sig.SignerCertificate.Subject -notlike '*Microsoft*' -or $sig.SignerCertificate.Issuer -notlike '*Microsoft Code Signing PCA*') { - # Copy for third party signing - Copy-Item -Path $_.FullName -Dest $netStandardPath -Force -Verbose - } - } - } - - # Set signing src path variable - $vstsCommandString = "vso[task.setvariable variable=signSrcPath]${thirdPartySignSrcPath}" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - - # Set signing out path variable - $vstsCommandString = "vso[task.setvariable variable=signOutPath]${signOutPath}" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Set up for module third party files code signing - condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - - - template: ./templates/sign.yml - parameters: - buildOutputPath: $(signSrcPath) - signOutputPath: $(signOutPath) - certificateId: "CP-231522" - pattern: '*.dll' - - - pwsh: | - $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' - $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath - $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject - Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" - Import-Module -Name $modPath -Force - - $config = Get-PSPackageProjectConfiguration - - $srcPath = "$($config.BuildOutputPath)\$($config.ModuleName)" - $signOutPath = "$($config.SignedOutputPath)\$($config.ModuleName)" - if (! (Test-Path -Path $signOutPath)) { - $null = New-Item -Path $signOutPath -ItemType Directory - } - - # en-US - Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "en-US") -Dest $signOutPath -Recurse - - # Net472 directory - $net472SignedOutPath = Join-Path -Path $signOutPath -ChildPath "net472" - if (! (Test-Path -Path $net472SignedOutPath)) { - $null = New-Item -Path $net472SignedOutPath -ItemType Directory -Verbose - } - Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "net472") -Filter '*.dll' | Foreach-Object { - if ($_.Name -ne 'PowerShellGet.dll') { - $sig = Get-AuthenticodeSignature -FilePath $_.FullName - if ($sig.Status -eq 'Valid' -and ($sig.SignerCertificate.Subject -like '*Microsoft*' -and $sig.SignerCertificate.Issuer -like '*Microsoft Code Signing PCA*')) { - # Copy already signed files directly to output - Copy-Item -Path $_.FullName -Dest $net472SignedOutPath -Force -Verbose - } - } - } - - # NetStandard directory - $netStandardSignedOutPath = Join-Path -Path $signOutPath -ChildPath "netstandard2.0" - if (! (Test-Path -Path $netStandardSignedOutPath)) { - $null = New-Item -Path $netStandardSignedOutPath -ItemType Directory -Verbose - } - Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "netstandard2.0") -Filter '*.dll' | Foreach-Object { - if ($_.Name -ne 'PowerShellGet.dll') { - $sig = Get-AuthenticodeSignature -FilePath $_.FullName - if ($sig.Status -eq 'Valid' -and ($sig.SignerCertificate.Subject -like '*Microsoft*' -and $sig.SignerCertificate.Issuer -like '*Microsoft Code Signing PCA*')) { - # Copy already signed files directly to output - Copy-Item -Path $_.FullName -Dest $netStandardSignedOutPath -Force -Verbose - } - } - } - displayName: Copy already properly signed third party files - condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - - - pwsh: | - $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' - $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath - $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject - Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" - Import-Module -Name $modPath -Force # - if ($env:SkipSigning -eq 'True') - { - $(Build.SourcesDirectory)/build.ps1 -Publish - } - else - { - $(Build.SourcesDirectory)/build.ps1 -Publish -Signed - } + $srcModulePath = Resolve-Path -Path "$($config.BuildOutputPath)/$($config.ModuleName)" + Get-ChildItem $srcModulePath + $artifactName = "$($config.ModuleName)" + Write-Host "##vso[artifact.upload containerfolder=$artifactName;artifactname=$artifactName;]$srcModulePath" + # + $(Build.SourcesDirectory)/build.ps1 -Publish displayName: Create module artifact - stage: Compliance @@ -294,9 +116,18 @@ stages: jobs: - job: ComplianceJob pool: - vmImage: windows-2019 + vmImage: windows-latest steps: - - template: compliance.yml + - checkout: self + clean: true + - checkout: ComplianceRepo + clean: true + - download: current + artifact: 'PowerShellGet' + - template: ci-compliance.yml@ComplianceRepo + parameters: + # credscan + suppressionsFile: '' - stage: Test displayName: Test Package @@ -306,13 +137,13 @@ stages: parameters: jobName: TestPkgWin displayName: PowerShell Core on Windows - imageName: windows-2019 + imageName: windows-latest - template: test.yml parameters: jobName: TestPkgWinPS displayName: Windows PowerShell on Windows - imageName: windows-2019 + imageName: windows-latest powershellExecutable: powershell # - template: test.yml @@ -326,9 +157,3 @@ stages: # jobName: TestPkgWinMacOS # displayName: PowerShell Core on macOS # imageName: macOS-10.14 - -- stage: Release - displayName: Release Package - condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), eq(variables['Publish'], 'True')) - jobs: - - template: release.yml diff --git a/.ci/compliance.yml b/.ci/compliance.yml deleted file mode 100644 index a0499dc62..000000000 --- a/.ci/compliance.yml +++ /dev/null @@ -1,105 +0,0 @@ -steps: - -- powershell: | - $powerShellPath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'powershell' - Invoke-WebRequest -Uri https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/install-powershell.ps1 -outfile ./install-powershell.ps1 - ./install-powershell.ps1 -Destination $powerShellPath - $vstsCommandString = "vso[task.setvariable variable=PATH]$powerShellPath;$env:PATH" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Install PowerShell Core - -- task: DownloadBuildArtifacts@0 - displayName: 'Download artifacts' - inputs: - buildType: current - downloadType: specific - itemPattern: '**/*.nupkg' - downloadPath: '$(System.ArtifactsDirectory)' - -- pwsh: | - Get-ChildItem -Path "$(System.ArtifactsDirectory)" -Recurse - displayName: Capture artifacts directory - -- pwsh: | - $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' - if (Test-Path -Path $modulePath) { - Write-Verbose -Verbose "Deleting existing temp module path: $modulePath" - Remove-Item -Path $modulePath -Recurse -Force -ErrorAction Ignore - } - if (! (Test-Path -Path $modulePath)) { - Write-Verbose -Verbose "Creating new temp module path: $modulePath" - $null = New-Item -Path $modulePath -ItemType Directory - } - displayName: Create temporary module path - -- pwsh: | - $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' - Write-Verbose -Verbose "Install PowerShellGet V3 to temp module path" - Save-Module -Name PowerShellGet -Path $modulePath -MinimumVersion 3.0.0-beta10 -AllowPrerelease -Force - Write-Verbose -Verbose "Install PlatyPS to temp module path" - Save-Module -Name "platyPS" -Path $modulePath -Force - Write-Verbose -Verbose "Install PSScriptAnalyzer to temp module path" - Save-Module -Name "PSScriptAnalyzer" -Path $modulePath -RequiredVersion 1.18.0 -Force - Write-Verbose -Verbose "Install Pester 4.X to temp module path" - Save-Module -Name "Pester" -MaximumVersion 4.99 -Path $modulePath -Force - Write-Verbose -Verbose "Install PSPackageProject to temp module path" - Save-Module -Name PSPackageProject -Path $modulePath -Force - displayName: Install PSPackageProject and dependencies - -- pwsh: | - $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' - $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath - $sourceName = 'pspackageproject-local-repo' - Register-PackageSource -Name $sourceName -Location "$(System.ArtifactsDirectory)" -ProviderName PowerShellGet -Force -ErrorAction Ignore - Get-PackageSource -Name $sourceName - $config = Get-PSPackageProjectConfiguration - $buildOutputPath = $config.BuildOutputPath - $null = New-Item -ItemType Directory -Path $buildOutputPath -Verbose - $moduleName = $config.ModuleName - Write-Verbose -Verbose "Saving package $sourceName to $($config.BuildOutputPath)" - Save-Package -Name $moduleName -Source $sourceName -ProviderName PowerShellGet -Path $config.BuildOutputPath -AllowPrereleaseVersions -Force - Write-Verbose -Verbose "Writing BUILD_SOURCE variable" - $vstsCommandString = "vso[task.setvariable variable=BUILD_SOURCE]$($config.BuildOutputPath)" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Extract product artifact - -- pwsh: | - $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' - $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath - $config = Get-PSPackageProjectConfiguration - dir "$($config.BuildOutputPath)/*" -r 2>$null - displayName: 'BuildOutputPath directory' - -- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(Build.SourcesDirectory)' - snapshotForceEnabled: true - -- task: securedevelopmentteam.vss-secure-development-tools.build-task-credscan.CredScan@2 - displayName: 'Run CredScan' - inputs: - toolMajorVersion: V2 - debugMode: false - continueOnError: true - -- task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@2 - displayName: 'Publish Security Analysis Logs to Build Artifacts' - continueOnError: true - -- task: securedevelopmentteam.vss-secure-development-tools.build-task-report.SdtReport@1 - displayName: 'Create Security Analysis Report' - inputs: - TsvFile: false - APIScan: false - BinSkim: false - CredScan: true - PoliCheck: true - PoliCheckBreakOn: Severity2Above - -- pwsh: | - Unregister-PSRepository -Name 'pspackageproject-local-repo' -ErrorAction Ignore - displayName: Unregister temporary PSRepository - condition: always() diff --git a/.ci/release.yml b/.ci/release.yml deleted file mode 100644 index 770bf6700..000000000 --- a/.ci/release.yml +++ /dev/null @@ -1,47 +0,0 @@ -parameters: - jobName: release - imageName: windows-2019 - displayName: 'Release PowerShellGet to NuGet' - -jobs: -- job: ${{ parameters.jobName }} - pool: - vmImage: ${{ parameters.imageName }} - displayName: ${{ parameters.displayName }} - - steps: - - task: NuGetToolInstaller@1 - displayName: 'Install NuGet 5.6.0' - inputs: - checkLatest: false - version: 5.6.0 - - - task: DownloadBuildArtifacts@0 - displayName: 'Download PowerShellGet module artifacts' - inputs: - buildType: current - downloadType: specific - artifactName: '**/*.nupkg' - downloadPath: '$(System.ArtifactsDirectory)' - - - powershell: | - Get-ChildItem '$(System.ArtifactsDirectory)/nupkg/PowerShellGet.*.nupkg' -ErrorAction SilentlyContinue - # Get-ChildItem '$(System.ArtifactsDirectory)' -Recurse - displayName: 'Capture PowerShellGet module NuGet package' - - # TODO: Need to create NuGet service connection - #- task: NuGetCommand@2 - # displayName: 'Push Microsoft.PowerShell.Store module artifacts to AzArtifactsFeed' - # inputs: - # command: push - # packagesToPush: '$(System.ArtifactsDirectory)/nupkg/PowerShellGet.*.nupkg' - # nuGetFeedType: external - # publishFeedCredentials: AzArtifactFeed - - #- task: NuGetCommand@2 - # displayName: 'Push Microsoft.PowerShell.Store module artifacts to PSGallery feed' - # inputs: - # command: push - # packagesToPush: '$(System.ArtifactsDirectory)/nupkg/PowerShellGet.*.nupkg' - # nuGetFeedType: external - # publishFeedCredentials: PHPowerShellGalleryFeed diff --git a/.ci/templates/sign.yml b/.ci/templates/sign.yml deleted file mode 100644 index 2e9ec940b..000000000 --- a/.ci/templates/sign.yml +++ /dev/null @@ -1,85 +0,0 @@ -parameters: - - name: "buildOutputPath" - default: "$(Build.ArtifactStagingDirectory)\\build" - - name: "signOutputPath" - default: "$(Build.ArtifactStagingDirectory)\\signed" - - name: "certificateId" - default: "CP-230012" - - name: "pattern" - default: "*.dll,*.exe" - -steps: -- task: UseDotNet@2 - displayName: 'Install .NET Core sdk 2.x for ESRP' - inputs: - version: 2.x - -- pwsh: | - [string] $CertificateId = "${{ parameters.certificateId }}" - Write-Verbose "CertificateId - $CertificateId" -Verbose - - [string] $VariableName = "EsrpJson" - - [string] $SigningServer = '$(SigningServer)' - Write-Verbose "SigningServer - $SigningServer" -Verbose - - $esrpParameters = @( - @{ - ParameterName = "OpusName" - ParameterValue = "Microsoft" - } - @{ - ParameterName = "OpusInfo" - ParameterValue = "http://www.microsoft.com" - } - @{ - ParameterName = "PageHash" - ParameterValue = "/NPH" - } - @{ - ParameterName = "FileDigest" - ParameterValue = "/fd sha256" - } - @{ - ParameterName = "TimeStamp" - ParameterValue = "/tr ""$SigningServer"" /td sha256" - } - ) - - $esrp = @(@{ - keyCode = $CertificateId - operationSetCode = "SigntoolSign" - parameters = $esrpParameters - toolName = "signtool.exe" - toolVersion = "6.2.9304.0" - }) - - $vstsCommandString = "vso[task.setvariable variable=$VariableName][$($esrp | ConvertTo-Json -Compress)]" - Write-Verbose -Message ("sending " + $vstsCommandString) -Verbose - Write-Host "##$vstsCommandString" - - $vstsCommandString = "vso[task.setvariable variable=GDN_CODESIGN_TARGETDIRECTORY]${{ parameters.signOutputPath }}" - Write-Verbose -Message ("sending " + $vstsCommandString) -Verbose - Write-Host "##$vstsCommandString" - displayName: Generate signing JSON - condition: and(and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')), ne(variables['SigningServer'], '')) - -- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 - displayName: Sign files - inputs: - ConnectedServiceName: pwshSigning - FolderPath: '${{ parameters.buildOutputPath }}' - UseMinimatch: false - signConfigType: inlineSignParams - inlineOperation: $(EsrpJson) - Pattern: ${{ parameters.pattern }} - condition: and(and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')), ne(variables['SigningServer'], '')) - -- pwsh: | - Write-Verbose "BUILD_OUTPUT_PATH- ${{ parameters.buildOutputPath }}" -Verbose - Write-Verbose "SIGNED_OUTPUT_PATH- ${{ parameters.signOutputPath }}" -Verbose - Copy-Item -Path ${{ parameters.buildOutputPath }}\* -Dest ${{ parameters.signOutputPath }}\ -Recurse -Force -Verbose - displayName: Copy signed files to signed output directory - condition: and(and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')), ne(variables['SigningServer'], '')) - timeoutInMinutes: 10 - \ No newline at end of file