@@ -30,9 +30,27 @@ parameters:
3030 image : win-x86_64-ado1es
3131 os : windows
3232
33+ - name : macos_matrix
34+ type : object
35+ default :
36+ - id : macos_x64
37+ jobName : ' macOS (x64)'
38+ runtime : osx-x64
39+ pool : ' Azure Pipelines'
40+ image : macOS-latest
41+ os : macos
42+ - id : macos_arm64
43+ jobName : ' macOS (ARM64)'
44+ runtime : osx-arm64
45+ pool : ' Azure Pipelines'
46+ image : macOS-latest
47+ os : macos
48+
3349variables :
3450 - name : ' esrpAppConnectionName'
3551 value : ' 1ESGitClient-ESRP-App'
52+ - name : ' esrpMIConnectionName'
53+ value : ' 1ESGitClient-ESRP-MI'
3654 # ESRP signing variables set in the pipeline settings:
3755 # - esrpEndpointUrl
3856 # - esrpClientId
@@ -204,3 +222,271 @@ extends:
204222 Copy-Item "$(Build.ArtifactStagingDirectory)\installers\*.zip" -Destination "$(Build.ArtifactStagingDirectory)\_final"
205223 Copy-Item "$(Build.ArtifactStagingDirectory)\symbols\*.zip" -Destination "$(Build.ArtifactStagingDirectory)\_final"
206224 Copy-Item "$(Build.ArtifactStagingDirectory)\payload" -Destination "$(Build.ArtifactStagingDirectory)\_final" -Recurse
225+
226+ #
227+ # macOS build jobs
228+ #
229+ - ${{ each dim in parameters.macos_matrix }} :
230+ - job : ${{ dim.id }}
231+ displayName : ${{ dim.jobName }}
232+ pool :
233+ name : ${{ dim.pool }}
234+ image : ${{ dim.image }}
235+ os : ${{ dim.os }}
236+ templateContext :
237+ outputs :
238+ - output : pipelineArtifact
239+ targetPath : ' $(Build.ArtifactStagingDirectory)/_final'
240+ artifactName : ' ${{ dim.runtime }}'
241+ steps :
242+ - checkout : self
243+ - task : Bash@3
244+ displayName : ' Read version file'
245+ inputs :
246+ targetType : inline
247+ script : |
248+ echo "##vso[task.setvariable variable=version;isReadOnly=true]$(cat ./VERSION | sed -E 's/.[0-9]+$//')"
249+ - task : UseDotNet@2
250+ displayName : ' Use .NET 8 SDK'
251+ inputs :
252+ packageType : sdk
253+ version : ' 8.x'
254+ - task : Bash@3
255+ displayName : ' Build payload'
256+ inputs :
257+ targetType : filePath
258+ filePath : ' ./src/osx/Installer.Mac/layout.sh'
259+ arguments : |
260+ --runtime="${{ dim.runtime }}" \
261+ --configuration="Release" \
262+ --output="$(Build.ArtifactStagingDirectory)/payload" \
263+ --symbol-output="$(Build.ArtifactStagingDirectory)/symbols_raw"
264+ - task : ArchiveFiles@2
265+ displayName : ' Archive symbols'
266+ inputs :
267+ rootFolderOrFile : ' $(Build.ArtifactStagingDirectory)/symbols_raw'
268+ includeRootFolder : false
269+ archiveType : tar
270+ tarCompression : gz
271+ archiveFile : ' $(Build.ArtifactStagingDirectory)/symbols/gcm-${{ dim.runtime }}-$(version)-symbols.tar.gz'
272+ - task : AzureKeyVault@2
273+ displayName : ' Download developer certificate'
274+ inputs :
275+ azureSubscription : ' $(esrpMIConnectionName)'
276+ keyVaultName : ' $(esrpKeyVaultName)'
277+ secretsFilter : ' mac-developer-certificate,mac-developer-certificate-password,mac-developer-certificate-identity'
278+ - task : Bash@3
279+ displayName : ' Import developer certificate'
280+ inputs :
281+ targetType : inline
282+ script : |
283+ # Create and unlock a keychain for the developer certificate
284+ security create-keychain -p pwd $(Agent.TempDirectory)/buildagent.keychain
285+ security default-keychain -s $(Agent.TempDirectory)/buildagent.keychain
286+ security unlock-keychain -p pwd $(Agent.TempDirectory)/buildagent.keychain
287+
288+ echo $(mac-developer-certificate) | base64 -D > $(Agent.TempDirectory)/cert.p12
289+ echo $(mac-developer-certificate-password) > $(Agent.TempDirectory)/cert.password
290+
291+ # Import the developer certificate
292+ security import $(Agent.TempDirectory)/cert.p12 \
293+ -k $(Agent.TempDirectory)/buildagent.keychain \
294+ -P "$(mac-developer-certificate-password)" \
295+ -T /usr/bin/codesign
296+
297+ # Clean up the cert file immediately after import
298+ rm $(Agent.TempDirectory)/cert.p12
299+
300+ # Set ACLs to allow codesign to access the private key
301+ security set-key-partition-list \
302+ -S apple-tool:,apple:,codesign: \
303+ -s -k pwd \
304+ $(Agent.TempDirectory)/buildagent.keychain
305+ - task : Bash@3
306+ displayName : ' Developer sign payload files'
307+ inputs :
308+ targetType : inline
309+ script : |
310+ mkdir -p $(Build.ArtifactStagingDirectory)/tosign/payload
311+
312+ # Copy the files that need signing (Mach-o executables and dylibs)
313+ pushd $(Build.ArtifactStagingDirectory)/payload
314+ find . -type f -exec file --mime {} + \
315+ | sed -n '/mach/s/: .*//p' \
316+ | while IFS= read -r f; do
317+ rel="${f#./}"
318+ tgt="$(Build.ArtifactStagingDirectory)/tosign/payload/$rel"
319+ mkdir -p "$(dirname "$tgt")"
320+ cp -- "$f" "$tgt"
321+ done
322+ popd
323+
324+ # Developer sign the files
325+ ./src/osx/Installer.Mac/codesign.sh \
326+ "$(Build.ArtifactStagingDirectory)/tosign/payload" \
327+ "$(mac-developer-certificate-identity)" \
328+ "$PWD/src/osx/Installer.Mac/entitlements.xml"
329+ # ESRP code signing for macOS requires the files be packaged in a zip file for submission
330+ - task : ArchiveFiles@2
331+ displayName : ' Archive files for signing'
332+ inputs :
333+ rootFolderOrFile : ' $(Build.ArtifactStagingDirectory)/tosign/payload'
334+ includeRootFolder : false
335+ archiveType : zip
336+ archiveFile : ' $(Build.ArtifactStagingDirectory)/tosign/payload.zip'
337+ - task : EsrpCodeSigning@5
338+ condition : and(succeeded(), eq('${{ parameters.esrp }}', true))
339+ displayName : ' Sign payload'
340+ inputs :
341+ connectedServiceName : ' $(esrpAppConnectionName)'
342+ useMSIAuthentication : true
343+ appRegistrationClientId : ' $(esrpClientId)'
344+ appRegistrationTenantId : ' $(esrpTenantId)'
345+ authAkvName : ' $(esrpKeyVaultName)'
346+ authSignCertName : ' $(esrpSignReqCertName)'
347+ serviceEndpointUrl : ' $(esrpEndpointUrl)'
348+ folderPath : ' $(Build.ArtifactStagingDirectory)/tosign'
349+ pattern : ' payload.zip'
350+ useMinimatch : true
351+ signConfigType : inlineSignParams
352+ inlineOperation : |
353+ [
354+ {
355+ "KeyCode": "CP-401337-Apple",
356+ "OperationCode": "MacAppDeveloperSign",
357+ "ToolName": "sign",
358+ "ToolVersion": "1.0",
359+ "Parameters": {
360+ "Hardening": "Enable"
361+ }
362+ }
363+ ]
364+ # Extract signed files, overwriting the unsigned files, ready for packaging
365+ - task : Bash@3
366+ displayName : ' Extract signed payload files'
367+ inputs :
368+ targetType : inline
369+ script : |
370+ unzip -uo $(Build.ArtifactStagingDirectory)/tosign/payload.zip -d $(Build.ArtifactStagingDirectory)/payload
371+ - task : Bash@3
372+ displayName : ' Build component package'
373+ inputs :
374+ targetType : filePath
375+ filePath : ' ./src/osx/Installer.Mac/pack.sh'
376+ arguments : |
377+ --version="$(version)" \
378+ --payload="$(Build.ArtifactStagingDirectory)/payload" \
379+ --output="$(Build.ArtifactStagingDirectory)/pkg/com.microsoft.gitcredentialmanager.component.pkg"
380+ - task : Bash@3
381+ displayName : ' Build installer package'
382+ inputs :
383+ targetType : filePath
384+ filePath : ' ./src/osx/Installer.Mac/dist.sh'
385+ arguments : |
386+ --version="$(version)" \
387+ --runtime="${{ dim.runtime }}" \
388+ --package-path="$(Build.ArtifactStagingDirectory)/pkg" \
389+ --output="$(Build.ArtifactStagingDirectory)/installers-presign/gcm-${{ dim.runtime }}-$(version).pkg"
390+ # ESRP code signing for macOS requires the files be packaged in a zip file first
391+ - task : Bash@3
392+ displayName : ' Prepare installer package for signing'
393+ inputs :
394+ targetType : inline
395+ script : |
396+ mkdir -p $(Build.ArtifactStagingDirectory)/tosign
397+ cd $(Build.ArtifactStagingDirectory)/installers-presign
398+ zip -rX $(Build.ArtifactStagingDirectory)/tosign/installers-presign.zip *.pkg
399+ - task : EsrpCodeSigning@5
400+ condition : and(succeeded(), eq('${{ parameters.esrp }}', true))
401+ displayName : ' Sign installer package'
402+ inputs :
403+ connectedServiceName : ' $(esrpAppConnectionName)'
404+ useMSIAuthentication : true
405+ appRegistrationClientId : ' $(esrpClientId)'
406+ appRegistrationTenantId : ' $(esrpTenantId)'
407+ authAkvName : ' $(esrpKeyVaultName)'
408+ authSignCertName : ' $(esrpSignReqCertName)'
409+ serviceEndpointUrl : ' $(esrpEndpointUrl)'
410+ folderPath : ' $(Build.ArtifactStagingDirectory)/tosign'
411+ pattern : ' installers-presign.zip'
412+ useMinimatch : true
413+ signConfigType : inlineSignParams
414+ inlineOperation : |
415+ [
416+ {
417+ "KeyCode": "CP-401337-Apple",
418+ "OperationCode": "MacAppDeveloperSign",
419+ "ToolName": "sign",
420+ "ToolVersion": "1.0",
421+ "Parameters": {
422+ "Hardening": "Enable"
423+ }
424+ }
425+ ]
426+ # Extract signed installer, overwriting the unsigned installer
427+ - task : Bash@3
428+ displayName : ' Extract signed installer package'
429+ inputs :
430+ targetType : inline
431+ script : |
432+ unzip -uo $(Build.ArtifactStagingDirectory)/tosign/installers-presign.zip -d $(Build.ArtifactStagingDirectory)/installers
433+ - task : Bash@3
434+ displayName : ' Prepare installer package for notarization'
435+ inputs :
436+ targetType : inline
437+ script : |
438+ mkdir -p $(Build.ArtifactStagingDirectory)/tosign
439+ cd $(Build.ArtifactStagingDirectory)/installers
440+ zip -rX $(Build.ArtifactStagingDirectory)/tosign/installers.zip *.pkg
441+ - task : EsrpCodeSigning@5
442+ condition : and(succeeded(), eq('${{ parameters.esrp }}', true))
443+ displayName : ' Notarize installer package'
444+ inputs :
445+ connectedServiceName : ' $(esrpAppConnectionName)'
446+ useMSIAuthentication : true
447+ appRegistrationClientId : ' $(esrpClientId)'
448+ appRegistrationTenantId : ' $(esrpTenantId)'
449+ authAkvName : ' $(esrpKeyVaultName)'
450+ authSignCertName : ' $(esrpSignReqCertName)'
451+ serviceEndpointUrl : ' $(esrpEndpointUrl)'
452+ folderPath : ' $(Build.ArtifactStagingDirectory)/tosign'
453+ pattern : ' installers.zip'
454+ useMinimatch : true
455+ signConfigType : inlineSignParams
456+ inlineOperation : |
457+ [
458+ {
459+ "KeyCode": "CP-401337-Apple",
460+ "OperationCode": "MacAppNotarize",
461+ "ToolName": "sign",
462+ "ToolVersion": "1.0",
463+ "Parameters": {
464+ "BundleId": "com.microsoft.gitcredentialmanager"
465+ }
466+ }
467+ ]
468+ # Extract signed and notarized installer pkg files, overwriting the unsigned files, ready for upload
469+ - task : Bash@3
470+ displayName : ' Extract signed and notarized installer package'
471+ inputs :
472+ targetType : inline
473+ script : |
474+ unzip -uo $(Build.ArtifactStagingDirectory)/tosign/installers.zip -d $(Build.ArtifactStagingDirectory)/installers
475+ - task : ArchiveFiles@2
476+ displayName : ' Archive signed payload'
477+ inputs :
478+ rootFolderOrFile : ' $(Build.ArtifactStagingDirectory)/payload'
479+ includeRootFolder : false
480+ archiveType : tar
481+ tarCompression : gz
482+ archiveFile : ' $(Build.ArtifactStagingDirectory)/installers/gcm-${{ dim.runtime }}-$(version).tar.gz'
483+ - task : Bash@3
484+ displayName : ' Collect artifacts for publishing'
485+ inputs :
486+ targetType : inline
487+ script : |
488+ mkdir -p $(Build.ArtifactStagingDirectory)/_final
489+ cp $(Build.ArtifactStagingDirectory)/installers/*.pkg $(Build.ArtifactStagingDirectory)/_final
490+ cp $(Build.ArtifactStagingDirectory)/installers/*.tar.gz $(Build.ArtifactStagingDirectory)/_final
491+ cp $(Build.ArtifactStagingDirectory)/symbols/*.tar.gz $(Build.ArtifactStagingDirectory)/_final
492+ cp -r $(Build.ArtifactStagingDirectory)/payload $(Build.ArtifactStagingDirectory)/_final
0 commit comments