зеркало из https://github.com/microsoft/git.git
build-git-installers: migrate macOS and Linux off ESRP (#614)
This PR migrates `microsoft/git`'s signing workflows off the ESRP service. This means: 1. Updating the Linux components to sign with a GPG key. 2. Updating macOS components to sign/notarize using Application and Installer certificates (see [this series](https://developer.apple.com/forums/thread/701514) for more details). An example run of release workflow with these changes can be found at [1]. 1: https://github.com/microsoft/git/actions/runs/6635788798
This commit is contained in:
Коммит
b7dec5ad71
|
@ -31,11 +31,16 @@ GIT_PREFIX := $(PREFIX)/git
|
|||
BUILD_CODE := $(ARCH_CODE)
|
||||
BUILD_DIR := $(GITHUB_WORKSPACE)/payload
|
||||
DESTDIR := $(PWD)/stage/git-$(BUILD_CODE)-$(VERSION)
|
||||
ARTIFACTDIR := build_artifacts
|
||||
ARTIFACTDIR := build-artifacts
|
||||
SUBMAKE := $(MAKE) C_INCLUDE_PATH="$(C_INCLUDE_PATH)" CPLUS_INCLUDE_PATH="$(CPLUS_INCLUDE_PATH)" LD_LIBRARY_PATH="$(LD_LIBRARY_PATH)" TARGET_FLAGS="$(TARGET_FLAGS)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" NO_GETTEXT=1 NO_DARWIN_PORTS=1 prefix=$(GIT_PREFIX) GIT_BUILT_FROM_COMMIT="$(GIT_BUILT_FROM_COMMIT)" DESTDIR=$(DESTDIR)
|
||||
CORES := $(shell bash -c "sysctl hw.ncpu | awk '{print \$$2}'")
|
||||
|
||||
.PHONY: image pkg payload
|
||||
# Guard against environment variables
|
||||
APPLE_APP_IDENTITY =
|
||||
APPLE_INSTALLER_IDENTITY =
|
||||
APPLE_KEYCHAIN_PROFILE =
|
||||
|
||||
.PHONY: image pkg payload codesign notarize
|
||||
|
||||
.SECONDARY:
|
||||
|
||||
|
@ -112,8 +117,17 @@ disk-image/VERSION-$(VERSION)-$(ARCH_CODE):
|
|||
mkdir disk-image
|
||||
touch "$@"
|
||||
|
||||
pkg_cmd := pkgbuild --identifier com.git.pkg --version $(VERSION) \
|
||||
--root $(ARTIFACTDIR)$(PREFIX) --scripts assets/scripts \
|
||||
--install-location $(PREFIX) --component-plist ./assets/git-components.plist
|
||||
|
||||
ifdef APPLE_INSTALLER_IDENTITY
|
||||
pkg_cmd += --sign "$(APPLE_INSTALLER_IDENTITY)"
|
||||
endif
|
||||
|
||||
pkg_cmd += disk-image/git-$(VERSION)-$(BUILD_CODE).pkg
|
||||
disk-image/git-$(VERSION)-$(BUILD_CODE).pkg: disk-image/VERSION-$(VERSION)-$(ARCH_CODE) symlinks
|
||||
pkgbuild --identifier com.git.pkg --version $(VERSION) --root $(ARTIFACTDIR)$(PREFIX) --scripts assets/scripts --install-location $(PREFIX) --component-plist ./assets/git-components.plist disk-image/git-$(VERSION)-$(BUILD_CODE).pkg
|
||||
$(pkg_cmd)
|
||||
|
||||
git-%-$(BUILD_CODE).dmg:
|
||||
hdiutil create git-$(VERSION)-$(BUILD_CODE).uncompressed.dmg -fs HFS+ -srcfolder disk-image -volname "Git $(VERSION) $(CPU_VENDOR) $(ARCH)" -ov
|
||||
|
@ -125,3 +139,18 @@ payload: $(BUILD_DIR)/git-$(VERSION)/osx-installed $(BUILD_DIR)/git-$(VERSION)/o
|
|||
pkg: disk-image/git-$(VERSION)-$(BUILD_CODE).pkg
|
||||
|
||||
image: git-$(VERSION)-$(BUILD_CODE).dmg
|
||||
|
||||
ifdef APPLE_APP_IDENTITY
|
||||
codesign:
|
||||
@$(CURDIR)/../scripts/codesign.sh --payload="build-artifacts/usr/local/git" \
|
||||
--identity="$(APPLE_APP_IDENTITY)" \
|
||||
--entitlements="$(CURDIR)/entitlements.xml"
|
||||
endif
|
||||
|
||||
# Notarization can only happen if the package is fully signed
|
||||
ifdef APPLE_KEYCHAIN_PROFILE
|
||||
notarize:
|
||||
@$(CURDIR)/../scripts/notarize.sh \
|
||||
--package="disk-image/git-$(VERSION)-$(BUILD_CODE).pkg" \
|
||||
--keychain-profile="$(APPLE_KEYCHAIN_PROFILE)"
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,65 @@
|
|||
#!/bin/bash
|
||||
|
||||
sign_directory () {
|
||||
(
|
||||
cd "$1"
|
||||
for f in *
|
||||
do
|
||||
macho=$(file --mime $f | grep mach)
|
||||
# Runtime sign dylibs and Mach-O binaries
|
||||
if [[ $f == *.dylib ]] || [ ! -z "$macho" ];
|
||||
then
|
||||
echo "Runtime Signing $f"
|
||||
codesign -s "$IDENTITY" $f --timestamp --force --options=runtime --entitlements $ENTITLEMENTS_FILE
|
||||
elif [ -d "$f" ];
|
||||
then
|
||||
echo "Signing files in subdirectory $f"
|
||||
sign_directory "$f"
|
||||
|
||||
else
|
||||
echo "Signing $f"
|
||||
codesign -s "$IDENTITY" $f --timestamp --force
|
||||
fi
|
||||
done
|
||||
)
|
||||
}
|
||||
|
||||
for i in "$@"
|
||||
do
|
||||
case "$i" in
|
||||
--payload=*)
|
||||
SIGN_DIR="${i#*=}"
|
||||
shift # past argument=value
|
||||
;;
|
||||
--identity=*)
|
||||
IDENTITY="${i#*=}"
|
||||
shift # past argument=value
|
||||
;;
|
||||
--entitlements=*)
|
||||
ENTITLEMENTS_FILE="${i#*=}"
|
||||
shift # past argument=value
|
||||
;;
|
||||
*)
|
||||
die "unknown option '$i'"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$SIGN_DIR" ]; then
|
||||
echo "error: missing directory argument"
|
||||
exit 1
|
||||
elif [ -z "$IDENTITY" ]; then
|
||||
echo "error: missing signing identity argument"
|
||||
exit 1
|
||||
elif [ -z "$ENTITLEMENTS_FILE" ]; then
|
||||
echo "error: missing entitlements file argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "======== INPUTS ========"
|
||||
echo "Directory: $SIGN_DIR"
|
||||
echo "Signing identity: $IDENTITY"
|
||||
echo "Entitlements: $ENTITLEMENTS_FILE"
|
||||
echo "======== END INPUTS ========"
|
||||
|
||||
sign_directory "$SIGN_DIR"
|
|
@ -0,0 +1,35 @@
|
|||
#!/bin/bash
|
||||
|
||||
for i in "$@"
|
||||
do
|
||||
case "$i" in
|
||||
--package=*)
|
||||
PACKAGE="${i#*=}"
|
||||
shift # past argument=value
|
||||
;;
|
||||
--keychain-profile=*)
|
||||
KEYCHAIN_PROFILE="${i#*=}"
|
||||
shift # past argument=value
|
||||
;;
|
||||
*)
|
||||
die "unknown option '$i'"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$PACKAGE" ]; then
|
||||
echo "error: missing package argument"
|
||||
exit 1
|
||||
elif [ -z "$KEYCHAIN_PROFILE" ]; then
|
||||
echo "error: missing keychain profile argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Exit as soon as any line fails
|
||||
set -e
|
||||
|
||||
# Send the notarization request
|
||||
xcrun notarytool submit -v "$PACKAGE" -p "$KEYCHAIN_PROFILE" --wait
|
||||
|
||||
# Staple the notarization ticket (to allow offline installation)
|
||||
xcrun stapler staple -v "$PACKAGE"
|
|
@ -1,135 +0,0 @@
|
|||
import argparse
|
||||
import json
|
||||
import os
|
||||
import glob
|
||||
import pprint
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
|
||||
parser = argparse.ArgumentParser(description='Sign binaries for macOS')
|
||||
parser.add_argument('path', help='Path to file for signing')
|
||||
parser.add_argument('keycode', help='Platform-specific key code for signing')
|
||||
parser.add_argument('opcode', help='Platform-specific operation code for signing')
|
||||
# Setting nargs=argparse.REMAINDER allows us to pass in params that begin with `--`
|
||||
parser.add_argument('--params', nargs=argparse.REMAINDER, help='Parameters for signing')
|
||||
args = parser.parse_args()
|
||||
|
||||
esrp_tool = os.path.join("esrp", "tools", "EsrpClient.exe")
|
||||
|
||||
aad_id = os.environ['AZURE_AAD_ID'].strip()
|
||||
workspace = os.environ['GITHUB_WORKSPACE'].strip()
|
||||
|
||||
source_location = args.path
|
||||
files = glob.glob(os.path.join(source_location, "*"))
|
||||
|
||||
print("Found files:")
|
||||
pprint.pp(files)
|
||||
|
||||
auth_json = {
|
||||
"Version": "1.0.0",
|
||||
"AuthenticationType": "AAD_CERT",
|
||||
"TenantId": "72f988bf-86f1-41af-91ab-2d7cd011db47",
|
||||
"ClientId": f"{aad_id}",
|
||||
"AuthCert": {
|
||||
"SubjectName": f"CN={aad_id}.microsoft.com",
|
||||
"StoreLocation": "LocalMachine",
|
||||
"StoreName": "My",
|
||||
"SendX5c" : "true"
|
||||
},
|
||||
"RequestSigningCert": {
|
||||
"SubjectName": f"CN={aad_id}",
|
||||
"StoreLocation": "LocalMachine",
|
||||
"StoreName": "My"
|
||||
}
|
||||
}
|
||||
|
||||
input_json = {
|
||||
"Version": "1.0.0",
|
||||
"SignBatches": [
|
||||
{
|
||||
"SourceLocationType": "UNC",
|
||||
"SourceRootDirectory": source_location,
|
||||
"DestinationLocationType": "UNC",
|
||||
"DestinationRootDirectory": workspace,
|
||||
"SignRequestFiles": [],
|
||||
"SigningInfo": {
|
||||
"Operations": [
|
||||
{
|
||||
"KeyCode": f"{args.keycode}",
|
||||
"OperationCode": f"{args.opcode}",
|
||||
"Parameters": {},
|
||||
"ToolName": "sign",
|
||||
"ToolVersion": "1.0",
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# add files to sign
|
||||
for f in files:
|
||||
name = os.path.basename(f)
|
||||
input_json["SignBatches"][0]["SignRequestFiles"].append(
|
||||
{
|
||||
"SourceLocation": name,
|
||||
"DestinationLocation": os.path.join("signed", name),
|
||||
}
|
||||
)
|
||||
|
||||
# add parameters to input.json (e.g. enabling the hardened runtime for macOS)
|
||||
if args.params is not None:
|
||||
i = 0
|
||||
while i < len(args.params):
|
||||
input_json["SignBatches"][0]["SigningInfo"]["Operations"][0]["Parameters"][args.params[i]] = args.params[i + 1]
|
||||
i += 2
|
||||
|
||||
policy_json = {
|
||||
"Version": "1.0.0",
|
||||
"Intent": "production release",
|
||||
"ContentType": "binary",
|
||||
}
|
||||
|
||||
configs = [
|
||||
("auth.json", auth_json),
|
||||
("input.json", input_json),
|
||||
("policy.json", policy_json),
|
||||
]
|
||||
|
||||
for filename, data in configs:
|
||||
with open(filename, 'w') as fp:
|
||||
json.dump(data, fp)
|
||||
|
||||
# Run ESRP Client
|
||||
esrp_out = "esrp_out.json"
|
||||
result = subprocess.run(
|
||||
[esrp_tool, "sign",
|
||||
"-a", "auth.json",
|
||||
"-i", "input.json",
|
||||
"-p", "policy.json",
|
||||
"-o", esrp_out,
|
||||
"-l", "Verbose"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=workspace)
|
||||
|
||||
# Scrub log before printing
|
||||
log = re.sub(r'^.+Uploading.*to\s*destinationUrl\s*(.+?),.+$',
|
||||
'***',
|
||||
result.stdout,
|
||||
flags=re.IGNORECASE|re.MULTILINE)
|
||||
print(log)
|
||||
|
||||
if result.returncode != 0:
|
||||
print("Failed to run ESRPClient.exe")
|
||||
sys.exit(1)
|
||||
|
||||
if os.path.isfile(esrp_out):
|
||||
print("ESRP output json:")
|
||||
with open(esrp_out, 'r') as fp:
|
||||
pprint.pp(json.load(fp))
|
||||
|
||||
for file in files:
|
||||
if os.path.isfile(os.path.join("signed", file)):
|
||||
print(f"Success!\nSigned {file}")
|
|
@ -1,12 +0,0 @@
|
|||
# Install ESRP client
|
||||
az storage blob download --file esrp.zip --auth-mode login --account-name esrpsigningstorage --container signing-resources --name microsoft.esrpclient.1.2.76.nupkg
|
||||
Expand-Archive -Path esrp.zip -DestinationPath .\esrp
|
||||
|
||||
# Install certificates
|
||||
az keyvault secret download --vault-name "$env:AZURE_VAULT" --name "$env:AUTH_CERT" --file out.pfx
|
||||
certutil -f -importpfx out.pfx
|
||||
Remove-Item out.pfx
|
||||
|
||||
az keyvault secret download --vault-name "$env:AZURE_VAULT" --name "$env:REQUEST_SIGNING_CERT" --file out.pfx
|
||||
certutil -f -importpfx out.pfx
|
||||
Remove-Item out.pfx
|
|
@ -10,13 +10,9 @@ jobs:
|
|||
prereqs:
|
||||
runs-on: ubuntu-latest
|
||||
environment: release
|
||||
env:
|
||||
AZ_SUB: ${{ secrets.AZURE_SUBSCRIPTION }}
|
||||
AZ_CREDS: ${{ secrets.AZURE_CREDENTIALS }}
|
||||
outputs:
|
||||
tag_name: ${{ steps.tag.outputs.name }} # The full name of the tag, e.g. v2.32.0.vfs.0.0
|
||||
tag_version: ${{ steps.tag.outputs.version }} # The version number (without preceding "v"), e.g. 2.32.0.vfs.0.0
|
||||
deb_signable: ${{ steps.deb.outputs.signable }} # Whether the credentials needed to sign the .deb package are available
|
||||
steps:
|
||||
- name: Validate tag
|
||||
run: |
|
||||
|
@ -30,9 +26,6 @@ jobs:
|
|||
echo "name=${GITHUB_REF#refs/tags/}" >>$GITHUB_OUTPUT
|
||||
echo "version=${GITHUB_REF#refs/tags/v}" >>$GITHUB_OUTPUT
|
||||
id: tag
|
||||
- name: Determine whether signing certificates are present
|
||||
run: echo "signable=$([[ $AZ_SUB != '' && $AZ_CREDS != '' ]] && echo 'true' || echo 'false')" >>$GITHUB_OUTPUT
|
||||
id: deb
|
||||
- name: Clone git
|
||||
uses: actions/checkout@v3
|
||||
- name: Validate the tag identified with trigger
|
||||
|
@ -309,7 +302,7 @@ jobs:
|
|||
# End build Windows installers
|
||||
|
||||
# Build and sign Mac OSX installers & upload artifacts
|
||||
osx_build:
|
||||
create-macos-artifacts:
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
|
@ -321,6 +314,7 @@ jobs:
|
|||
needs: prereqs
|
||||
env:
|
||||
VERSION: "${{ needs.prereqs.outputs.tag_version }}"
|
||||
environment: release
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v3
|
||||
|
@ -333,7 +327,56 @@ jobs:
|
|||
brew install automake asciidoc xmlto docbook
|
||||
brew link --force gettext
|
||||
|
||||
- name: Build payload
|
||||
- name: Set up signing/notarization infrastructure
|
||||
env:
|
||||
A1: ${{ secrets.APPLICATION_CERTIFICATE_BASE64 }}
|
||||
A2: ${{ secrets.APPLICATION_CERTIFICATE_PASSWORD }}
|
||||
I1: ${{ secrets.INSTALLER_CERTIFICATE_BASE64 }}
|
||||
I2: ${{ secrets.INSTALLER_CERTIFICATE_PASSWORD }}
|
||||
N1: ${{ secrets.APPLE_TEAM_ID }}
|
||||
N2: ${{ secrets.APPLE_DEVELOPER_ID }}
|
||||
N3: ${{ secrets.APPLE_DEVELOPER_PASSWORD }}
|
||||
N4: ${{ secrets.APPLE_KEYCHAIN_PROFILE }}
|
||||
run: |
|
||||
echo "Setting up signing certificates"
|
||||
security create-keychain -p pwd $RUNNER_TEMP/buildagent.keychain
|
||||
security default-keychain -s $RUNNER_TEMP/buildagent.keychain
|
||||
security unlock-keychain -p pwd $RUNNER_TEMP/buildagent.keychain
|
||||
# Prevent re-locking
|
||||
security set-keychain-settings $RUNNER_TEMP/buildagent.keychain
|
||||
|
||||
echo "$A1" | base64 -D > $RUNNER_TEMP/cert.p12
|
||||
security import $RUNNER_TEMP/cert.p12 \
|
||||
-k $RUNNER_TEMP/buildagent.keychain \
|
||||
-P "$A2" \
|
||||
-T /usr/bin/codesign
|
||||
security set-key-partition-list \
|
||||
-S apple-tool:,apple:,codesign: \
|
||||
-s -k pwd \
|
||||
$RUNNER_TEMP/buildagent.keychain
|
||||
|
||||
echo "$I1" | base64 -D > $RUNNER_TEMP/cert.p12
|
||||
security import $RUNNER_TEMP/cert.p12 \
|
||||
-k $RUNNER_TEMP/buildagent.keychain \
|
||||
-P "$I2" \
|
||||
-T /usr/bin/pkgbuild
|
||||
security set-key-partition-list \
|
||||
-S apple-tool:,apple:,pkgbuild: \
|
||||
-s -k pwd \
|
||||
$RUNNER_TEMP/buildagent.keychain
|
||||
|
||||
echo "Setting up notarytool"
|
||||
xcrun notarytool store-credentials \
|
||||
--team-id "$N1" \
|
||||
--apple-id "$N2" \
|
||||
--password "$N3" \
|
||||
"$N4"
|
||||
|
||||
- name: Build, sign, and notarize artifacts
|
||||
env:
|
||||
A3: ${{ secrets.APPLE_APPLICATION_SIGNING_IDENTITY }}
|
||||
I3: ${{ secrets.APPLE_INSTALLER_SIGNING_IDENTITY }}
|
||||
N4: ${{ secrets.APPLE_KEYCHAIN_PROFILE }}
|
||||
run: |
|
||||
die () {
|
||||
echo "$*" >&2
|
||||
|
@ -375,290 +418,55 @@ jobs:
|
|||
# Lay out payload
|
||||
make -C git/.github/macos-installer V=1 payload
|
||||
|
||||
# This step is necessary because we cannot use the $VERSION
|
||||
# environment variable or the tag_version output from the prereqs
|
||||
# job in the upload-artifact task.
|
||||
mkdir -p build_artifacts
|
||||
cp -R stage/git-${{ matrix.arch.name }}-$VERSION/ build_artifacts
|
||||
# Codesign payload
|
||||
cp -R stage/git-${{ matrix.arch.name }}-$VERSION/ \
|
||||
git/.github/macos-installer/build-artifacts
|
||||
make -C git/.github/macos-installer V=1 codesign \
|
||||
APPLE_APP_IDENTITY="$A3" || die "Creating signed payload failed"
|
||||
|
||||
# We keep a list of executable files because their executable bits are
|
||||
# removed when they are zipped, and we need to re-add.
|
||||
find build_artifacts -type f -a -perm -u=x >executable-files.txt
|
||||
# Build and sign pkg
|
||||
make -C git/.github/macos-installer V=1 pkg \
|
||||
APPLE_INSTALLER_IDENTITY="$I3" \
|
||||
|| die "Creating signed pkg failed"
|
||||
|
||||
- name: Upload macOS artifacts
|
||||
# Notarize pkg
|
||||
make -C git/.github/macos-installer V=1 notarize \
|
||||
APPLE_INSTALLER_IDENTITY="$I3" APPLE_KEYCHAIN_PROFILE="$N4" \
|
||||
|| die "Creating signed and notarized pkg failed"
|
||||
|
||||
# Create DMG
|
||||
make -C git/.github/macos-installer V=1 image || die "Creating DMG failed"
|
||||
|
||||
# Move all artifacts into top-level directory
|
||||
mv git/.github/macos-installer/disk-image/*.pkg git/.github/macos-installer/
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: tmp.osx-${{ matrix.arch.name }}-build
|
||||
name: macos-artifacts
|
||||
path: |
|
||||
build_artifacts
|
||||
|
||||
- name: Upload list of executable files
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: tmp.executable-files
|
||||
path: |
|
||||
executable-files.txt
|
||||
|
||||
osx_sign_payload:
|
||||
# ESRP service requires signing to run on Windows
|
||||
runs-on: windows-latest
|
||||
environment: release
|
||||
needs: osx_build
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: 'git'
|
||||
|
||||
- name: Download unsigned build artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: tmp.osx-${{ matrix.arch }}-build
|
||||
path: build_artifacts
|
||||
|
||||
- name: Zip unsigned build artifacts
|
||||
shell: pwsh
|
||||
run: |
|
||||
Compress-Archive -Path build_artifacts build_artifacts/build_artifacts.zip
|
||||
cd build_artifacts
|
||||
Get-ChildItem -Exclude build_artifacts.zip | Remove-Item -Recurse -Force
|
||||
|
||||
- uses: azure/login@v1
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_CREDENTIALS }}
|
||||
|
||||
- name: Set up ESRP client
|
||||
shell: pwsh
|
||||
env:
|
||||
AZURE_VAULT: ${{ secrets.AZURE_VAULT }}
|
||||
AUTH_CERT: ${{ secrets.AZURE_VAULT_AUTH_CERT_NAME }}
|
||||
REQUEST_SIGNING_CERT: ${{ secrets.AZURE_VAULT_REQUEST_SIGNING_CERT_NAME }}
|
||||
run: |
|
||||
git\.github\scripts\set-up-esrp.ps1
|
||||
|
||||
- name: Run ESRP client
|
||||
shell: pwsh
|
||||
env:
|
||||
AZURE_AAD_ID: ${{ secrets.AZURE_AAD_ID }}
|
||||
APPLE_KEY_CODE: ${{ secrets.APPLE_KEY_CODE }}
|
||||
APPLE_SIGNING_OP_CODE: ${{ secrets.APPLE_SIGNING_OPERATION_CODE }}
|
||||
run: |
|
||||
python git\.github\scripts\run-esrp-signing.py build_artifacts `
|
||||
$env:APPLE_KEY_CODE $env:APPLE_SIGNING_OP_CODE `
|
||||
--params 'Hardening' '--options=runtime'
|
||||
|
||||
- name: Unzip signed build artifacts
|
||||
shell: pwsh
|
||||
run: |
|
||||
Expand-Archive signed/build_artifacts.zip -DestinationPath signed
|
||||
Remove-Item signed/build_artifacts.zip
|
||||
|
||||
- name: Upload signed payload
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: osx-signed-${{ matrix.arch }}-payload
|
||||
path: |
|
||||
signed
|
||||
|
||||
osx_pack:
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
- name: x86_64
|
||||
runner: macos-latest
|
||||
- name: arm64
|
||||
runner: macos-latest-xl-arm64
|
||||
runs-on: ${{ matrix.arch.runner }}
|
||||
needs: [prereqs, osx_sign_payload]
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: 'git'
|
||||
|
||||
- name: Download signed artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: osx-signed-${{ matrix.arch.name }}-payload
|
||||
|
||||
- name: Download list of executable files
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: tmp.executable-files
|
||||
|
||||
- name: Build macOS pkg
|
||||
env:
|
||||
VERSION: "${{ needs.prereqs.outputs.tag_version }}"
|
||||
run: |
|
||||
die () {
|
||||
echo "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
set -ex
|
||||
|
||||
# Install findutils to use gxargs below
|
||||
brew install findutils
|
||||
|
||||
# Configure the environment
|
||||
export CURL_LDFLAGS=$(curl-config --libs)
|
||||
|
||||
# Add executable bits and move build_artifacts into
|
||||
# the same directory as Makefile (so that executable bits
|
||||
# will be recognized).
|
||||
gxargs -r -d '\n' chmod a+x <executable-files.txt
|
||||
mv build_artifacts git/.github/macos-installer/
|
||||
|
||||
# Create pkg
|
||||
PATH=/usr/local/bin:$PATH \
|
||||
make -C git/.github/macos-installer V=1 pkg ||
|
||||
die "Build failed"
|
||||
|
||||
- name: Upload unsigned pkg
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: tmp.osx-${{ matrix.arch.name }}-pkg
|
||||
path: |
|
||||
git/.github/macos-installer/disk-image
|
||||
|
||||
osx_sign_and_notarize_pkg:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
# ESRP service requires signing to run on Windows
|
||||
runs-on: windows-latest
|
||||
environment: release
|
||||
needs: osx_pack
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: 'git'
|
||||
|
||||
- name: Download unsigned package
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: tmp.osx-${{ matrix.arch }}-pkg
|
||||
path: pkg
|
||||
|
||||
- name: Zip unsigned package
|
||||
shell: pwsh
|
||||
run: |
|
||||
Compress-Archive -Path pkg/*.pkg pkg/msft-git-pkg.zip
|
||||
cd pkg
|
||||
Get-ChildItem -Exclude msft-git-pkg.zip | Remove-Item -Recurse -Force
|
||||
|
||||
- uses: azure/login@v1
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_CREDENTIALS }}
|
||||
|
||||
- name: Set up ESRP client
|
||||
shell: pwsh
|
||||
env:
|
||||
AZURE_VAULT: ${{ secrets.AZURE_VAULT }}
|
||||
AUTH_CERT: ${{ secrets.AZURE_VAULT_AUTH_CERT_NAME }}
|
||||
REQUEST_SIGNING_CERT: ${{ secrets.AZURE_VAULT_REQUEST_SIGNING_CERT_NAME }}
|
||||
run: |
|
||||
git\.github\scripts\set-up-esrp.ps1
|
||||
|
||||
- name: Sign package
|
||||
shell: pwsh
|
||||
env:
|
||||
AZURE_AAD_ID: ${{ secrets.AZURE_AAD_ID }}
|
||||
APPLE_KEY_CODE: ${{ secrets.APPLE_KEY_CODE }}
|
||||
APPLE_SIGNING_OP_CODE: ${{ secrets.APPLE_SIGNING_OPERATION_CODE }}
|
||||
run: |
|
||||
python git\.github\scripts\run-esrp-signing.py pkg $env:APPLE_KEY_CODE $env:APPLE_SIGNING_OP_CODE
|
||||
|
||||
- name: Unzip signed package
|
||||
shell: pwsh
|
||||
run: |
|
||||
mkdir unsigned
|
||||
Expand-Archive -LiteralPath signed\msft-git-pkg.zip -DestinationPath .\unsigned -Force
|
||||
Remove-Item signed\msft-git-pkg.zip -Force
|
||||
|
||||
- name: Notarize signed package
|
||||
shell: pwsh
|
||||
env:
|
||||
AZURE_AAD_ID: ${{ secrets.AZURE_AAD_ID }}
|
||||
APPLE_KEY_CODE: ${{ secrets.APPLE_KEY_CODE }}
|
||||
APPLE_NOTARIZATION_OP_CODE: ${{ secrets.APPLE_NOTARIZATION_OPERATION_CODE }}
|
||||
run: |
|
||||
python git\.github\scripts\run-esrp-signing.py unsigned $env:APPLE_KEY_CODE `
|
||||
$env:APPLE_NOTARIZATION_OP_CODE --params 'BundleId' 'com.microsoft.git'
|
||||
|
||||
- name: Upload signed and notarized pkg
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: osx-signed-${{ matrix.arch }}-pkg
|
||||
path: |
|
||||
signed
|
||||
|
||||
osx_publish_dmg:
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
- name: x86_64
|
||||
runner: macos-latest
|
||||
- name: arm64
|
||||
runner: macos-latest-xl-arm64
|
||||
runs-on: ${{ matrix.arch.runner }}
|
||||
needs: [prereqs, osx_sign_and_notarize_pkg]
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: 'git'
|
||||
|
||||
- name: Download signed package
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: osx-signed-${{ matrix.arch.name }}-pkg
|
||||
path: disk-image
|
||||
|
||||
- name: Build macOS disk image
|
||||
env:
|
||||
VERSION: "${{ needs.prereqs.outputs.tag_version }}"
|
||||
run: |
|
||||
die () {
|
||||
echo "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
set -ex
|
||||
|
||||
# Move disk-image into the same directory as Makefile
|
||||
mv disk-image git/.github/macos-installer/
|
||||
|
||||
PATH=/usr/local/bin:$PATH \
|
||||
make -C git/.github/macos-installer V=1 image || die "Build failed"
|
||||
|
||||
- name: Publish disk image
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: osx-${{ matrix.arch.name }}-dmg
|
||||
path: git/.github/macos-installer/*.dmg
|
||||
git/.github/macos-installer/*.dmg
|
||||
git/.github/macos-installer/*.pkg
|
||||
# End build and sign Mac OSX installers
|
||||
|
||||
# Build & sign Ubuntu package
|
||||
ubuntu_build:
|
||||
runs-on: ubuntu-20.04
|
||||
# Build and sign Debian package
|
||||
create-linux-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
needs: prereqs
|
||||
environment: release
|
||||
steps:
|
||||
- name: Install git dependencies
|
||||
run: |
|
||||
set -ex
|
||||
|
||||
sudo apt-get update -q
|
||||
sudo apt-get install -y -q --no-install-recommends gettext libcurl4-gnutls-dev libpcre3-dev asciidoc xmlto
|
||||
|
||||
- name: Clone git
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: git
|
||||
- name: Build and package .deb
|
||||
|
||||
- name: Build and create Debian package
|
||||
run: |
|
||||
set -ex
|
||||
|
||||
|
@ -710,57 +518,56 @@ jobs:
|
|||
specialized in supporting monorepo scenarios. Includes the Scalar CLI.
|
||||
EOF
|
||||
|
||||
dpkg-deb --build "$PKGNAME"
|
||||
dpkg-deb -Zxz --build "$PKGNAME"
|
||||
# Move Debian package for later artifact upload
|
||||
mv "$PKGNAME.deb" "$GITHUB_WORKSPACE"
|
||||
|
||||
mkdir $GITHUB_WORKSPACE/artifacts
|
||||
mv "$PKGNAME.deb" $GITHUB_WORKSPACE/artifacts/
|
||||
- name: Publish unsigned .deb package
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: deb-package-unsigned
|
||||
path: artifacts/
|
||||
ubuntu_sign-artifacts:
|
||||
runs-on: windows-latest # Must be run on Windows due to ESRP executable OS compatibility
|
||||
environment: release
|
||||
needs: [ubuntu_build, prereqs]
|
||||
if: needs.prereqs.outputs.deb_signable == 'true'
|
||||
env:
|
||||
ARTIFACTS_DIR: artifacts
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: 'git'
|
||||
- name: Download unsigned packages
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: deb-package-unsigned
|
||||
path: unsigned
|
||||
- uses: azure/login@v1
|
||||
- name: Log into Azure
|
||||
uses: azure/login@v1
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_CREDENTIALS }}
|
||||
- name: Set up ESRP client
|
||||
shell: pwsh
|
||||
|
||||
- name: Prepare for GPG signing
|
||||
env:
|
||||
AZURE_VAULT: ${{ secrets.AZURE_VAULT }}
|
||||
AUTH_CERT: ${{ secrets.AZURE_VAULT_AUTH_CERT_NAME }}
|
||||
REQUEST_SIGNING_CERT: ${{ secrets.AZURE_VAULT_REQUEST_SIGNING_CERT_NAME }}
|
||||
GPG_KEY_SECRET_NAME: ${{ secrets.GPG_KEY_SECRET_NAME }}
|
||||
GPG_PASSPHRASE_SECRET_NAME: ${{ secrets.GPG_PASSPHRASE_SECRET_NAME }}
|
||||
GPG_KEYGRIP_SECRET_NAME: ${{ secrets.GPG_KEYGRIP_SECRET_NAME }}
|
||||
run: |
|
||||
git\.github\scripts\set-up-esrp.ps1
|
||||
- name: Sign package
|
||||
shell: pwsh
|
||||
env:
|
||||
AZURE_AAD_ID: ${{ secrets.AZURE_AAD_ID }}
|
||||
LINUX_KEY_CODE: ${{ secrets.LINUX_KEY_CODE }}
|
||||
LINUX_OP_CODE: ${{ secrets.LINUX_OPERATION_CODE }}
|
||||
# Install debsigs
|
||||
sudo apt install debsigs
|
||||
|
||||
# Download GPG key, passphrase, and keygrip from Azure Key Vault
|
||||
key=$(az keyvault secret show --name $GPG_KEY_SECRET_NAME --vault-name $AZURE_VAULT --query "value")
|
||||
passphrase=$(az keyvault secret show --name $GPG_PASSPHRASE_SECRET_NAME --vault-name $AZURE_VAULT --query "value")
|
||||
keygrip=$(az keyvault secret show --name $GPG_KEYGRIP_SECRET_NAME --vault-name $AZURE_VAULT --query "value")
|
||||
|
||||
# Remove quotes from downloaded values
|
||||
key=$(sed -e 's/^"//' -e 's/"$//' <<<"$key")
|
||||
passphrase=$(sed -e 's/^"//' -e 's/"$//' <<<"$passphrase")
|
||||
keygrip=$(sed -e 's/^"//' -e 's/"$//' <<<"$keygrip")
|
||||
|
||||
# Import GPG key
|
||||
echo "$key" | base64 -d | gpg --import --no-tty --batch --yes
|
||||
|
||||
# Configure GPG
|
||||
echo "allow-preset-passphrase" > ~/.gnupg/gpg-agent.conf
|
||||
gpg-connect-agent RELOADAGENT /bye
|
||||
/usr/lib/gnupg2/gpg-preset-passphrase --preset "$keygrip" <<<"$passphrase"
|
||||
|
||||
- name: Sign Debian package
|
||||
run: |
|
||||
python git\.github\scripts\run-esrp-signing.py unsigned $env:LINUX_KEY_CODE $env:LINUX_OP_CODE
|
||||
- name: Upload signed artifact
|
||||
# Sign Debian package
|
||||
version="${{ needs.prereqs.outputs.tag_version }}"
|
||||
debsigs --sign=origin --verify --check microsoft-git_"$version".deb
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: deb-package-signed
|
||||
path: signed
|
||||
# End build & sign Ubuntu package
|
||||
name: linux-artifacts
|
||||
path: |
|
||||
*.deb
|
||||
# End build and sign Debian package
|
||||
|
||||
# Validate installers
|
||||
validate-installers:
|
||||
|
@ -769,19 +576,19 @@ jobs:
|
|||
matrix:
|
||||
component:
|
||||
- os: ubuntu-latest
|
||||
artifact: deb-package-signed
|
||||
artifact: linux-artifacts
|
||||
command: git
|
||||
- os: macos-latest-xl-arm64
|
||||
artifact: osx-signed-arm64-pkg
|
||||
artifact: macos-artifacts
|
||||
command: git
|
||||
- os: macos-latest
|
||||
artifact: osx-signed-x86_64-pkg
|
||||
artifact: macos-artifacts
|
||||
command: git
|
||||
- os: windows-latest
|
||||
artifact: win-installer-x86_64
|
||||
command: $PROGRAMFILES\Git\cmd\git.exe
|
||||
runs-on: ${{ matrix.component.os }}
|
||||
needs: [prereqs, windows_artifacts, osx_publish_dmg, ubuntu_sign-artifacts]
|
||||
needs: [prereqs, windows_artifacts, create-macos-artifacts, create-linux-artifacts]
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
|
@ -805,10 +612,11 @@ jobs:
|
|||
if: contains(matrix.component.os, 'macos')
|
||||
run: |
|
||||
# avoid letting Homebrew's `git` in `/opt/homebrew/bin` override `/usr/local/bin/git`
|
||||
test arm64 != "$(uname -m)" ||
|
||||
arch="$(uname -m)"
|
||||
test arm64 != "$arch" ||
|
||||
brew uninstall git
|
||||
|
||||
pkgpath=$(find ./*.pkg)
|
||||
pkgpath=$(find ./*$arch*.pkg)
|
||||
sudo installer -pkg $pkgpath -target /
|
||||
|
||||
- name: Validate
|
||||
|
@ -822,10 +630,14 @@ jobs:
|
|||
create-github-release:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [validate-installers]
|
||||
env:
|
||||
AZURE_VAULT: ${{ secrets.AZURE_VAULT }}
|
||||
GPG_PUBLIC_KEY_SECRET_NAME: ${{ secrets.GPG_PUBLIC_KEY_SECRET_NAME }}
|
||||
environment: release
|
||||
if: |
|
||||
success() ||
|
||||
(needs.ubuntu_sign-artifacts.result == 'skipped' &&
|
||||
needs.osx_publish_dmg.result == 'success' &&
|
||||
(needs.create-linux-artifacts.result == 'skipped' &&
|
||||
needs.create-macos-artifacts.result == 'success' &&
|
||||
needs.windows_artifacts.result == 'success')
|
||||
steps:
|
||||
- name: Download Windows portable installer
|
||||
|
@ -833,43 +645,37 @@ jobs:
|
|||
with:
|
||||
name: win-portable-x86_64
|
||||
path: win-portable-x86_64
|
||||
|
||||
- name: Download Windows x86_64 installer
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: win-installer-x86_64
|
||||
path: win-installer-x86_64
|
||||
- name: Download Mac x86_64 dmg
|
||||
|
||||
- name: Download macOS artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: osx-x86_64-dmg
|
||||
path: osx-dmg
|
||||
- name: Download Mac ARM64 dmg
|
||||
name: macos-artifacts
|
||||
path: macos-artifacts
|
||||
|
||||
- name: Download Debian package
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: osx-arm64-dmg
|
||||
path: osx-dmg
|
||||
- name: Download Mac x86_64 pkg
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: osx-signed-x86_64-pkg
|
||||
path: osx-pkg
|
||||
- name: Download Mac ARM64 pkg
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: osx-signed-arm64-pkg
|
||||
path: osx-pkg
|
||||
- name: Download Ubuntu package (signed)
|
||||
if: needs.prereqs.outputs.deb_signable == 'true'
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: deb-package-signed
|
||||
name: linux-artifacts
|
||||
path: deb-package
|
||||
- name: Download Ubuntu package (unsigned)
|
||||
if: needs.prereqs.outputs.deb_signable != 'true'
|
||||
uses: actions/download-artifact@v3
|
||||
|
||||
- name: Log into Azure
|
||||
uses: azure/login@v1
|
||||
with:
|
||||
name: deb-package-unsigned
|
||||
path: deb-package
|
||||
creds: ${{ secrets.AZURE_CREDENTIALS }}
|
||||
|
||||
- name: Download GPG public key signature file
|
||||
run: |
|
||||
az keyvault secret show --name "$GPG_PUBLIC_KEY_SECRET_NAME" \
|
||||
--vault-name "$AZURE_VAULT" --query "value" \
|
||||
| sed -e 's/^"//' -e 's/"$//' | base64 -d >msft-git-public.asc
|
||||
mv msft-git-public.asc deb-package
|
||||
|
||||
- uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
|
@ -918,8 +724,7 @@ jobs:
|
|||
uploadDirectoryToRelease('win-portable-x86_64', ['.exe']),
|
||||
|
||||
// Upload Mac artifacts
|
||||
uploadDirectoryToRelease('osx-dmg'),
|
||||
uploadDirectoryToRelease('osx-pkg'),
|
||||
uploadDirectoryToRelease('macos-artifacts'),
|
||||
|
||||
// Upload Ubuntu artifacts
|
||||
uploadDirectoryToRelease('deb-package')
|
||||
|
|
55
README.md
55
README.md
|
@ -114,12 +114,59 @@ Or you can run the `git update-microsoft-git` command, which will run those brew
|
|||
## Linux
|
||||
### Ubuntu/Debian distributions
|
||||
|
||||
On newer distributions*, you can download the most recent Debian package from
|
||||
the [releases page](https://github.com/microsoft/git/releases/latest) (or
|
||||
using a tool such as `wget`) then run:
|
||||
On newer distributions*, you can install using the most recent Debian package.
|
||||
To download and validate the signature of this package, run the following:
|
||||
|
||||
```shell
|
||||
sudo dpkg -i <path to package>
|
||||
# Install needed packages
|
||||
apt-get install -y curl debsig-verify
|
||||
|
||||
# Download public key signature file
|
||||
curl -s https://api.github.com/repos/microsoft/git/releases/latest \
|
||||
| grep -E 'browser_download_url.*msft-git-public.asc' \
|
||||
| cut -d : -f 2,3 \
|
||||
| tr -d \" \
|
||||
| xargs -I 'url' curl -L -o msft-git-public.asc 'url'
|
||||
|
||||
# De-armor public key signature file
|
||||
gpg --output msft-git-public.gpg --dearmor msft-git-public.asc
|
||||
|
||||
# Note that the fingerprint of this key is "B8F12E25441124E1", which you can
|
||||
# determine by running:
|
||||
gpg --show-keys msft-git-public.asc | head -n 2 | tail -n 1 | tail -c 17
|
||||
|
||||
# Copy de-armored public key to debsig keyring folder
|
||||
mkdir /usr/share/debsig/keyrings/B8F12E25441124E1
|
||||
mv msft-git-public.gpg /usr/share/debsig/keyrings/B8F12E25441124E1/
|
||||
|
||||
# Create an appropriate policy file
|
||||
mkdir /etc/debsig/policies/B8F12E25441124E1
|
||||
cat > /etc/debsig/policies/B8F12E25441124E1/generic.pol << EOL
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Policy SYSTEM "https://www.debian.org/debsig/1.0/policy.dtd">
|
||||
<Policy xmlns="https://www.debian.org/debsig/1.0/">
|
||||
<Origin Name="Microsoft Git" id="B8F12E25441124E1" Description="Microsoft Git public key"/>
|
||||
<Selection>
|
||||
<Required Type="origin" File="msft-git-public.gpg" id="B8F12E25441124E1"/>
|
||||
</Selection>
|
||||
<Verification MinOptional="0">
|
||||
<Required Type="origin" File="msft-git-public.gpg" id="B8F12E25441124E1"/>
|
||||
</Verification>
|
||||
</Policy>
|
||||
EOL
|
||||
|
||||
# Download Debian package
|
||||
curl -s https://api.github.com/repos/microsoft/git/releases/latest \
|
||||
| grep "browser_download_url.*deb" \
|
||||
| cut -d : -f 2,3 \
|
||||
| tr -d \" \
|
||||
| xargs -I 'url' curl -L -o msft-git.deb 'url'
|
||||
|
||||
# Verify
|
||||
debsig-verify msft-git.deb
|
||||
|
||||
# Install
|
||||
sudo dpkg -i msft-git.deb
|
||||
```
|
||||
|
||||
Double-check that you have the right version by running these commands,
|
||||
|
|
Загрузка…
Ссылка в новой задаче