diff --git a/.github/macos-installer/Makefile b/.github/macos-installer/Makefile
index fa7cfe9eb77e4a..cba8bf5a890d1d 100644
--- a/.github/macos-installer/Makefile
+++ b/.github/macos-installer/Makefile
@@ -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
diff --git a/.github/macos-installer/entitlements.xml b/.github/macos-installer/entitlements.xml
new file mode 100644
index 00000000000000..46f675661149b6
--- /dev/null
+++ b/.github/macos-installer/entitlements.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ com.apple.security.cs.allow-jit
+
+ com.apple.security.cs.allow-unsigned-executable-memory
+
+ com.apple.security.cs.disable-library-validation
+
+
+
diff --git a/.github/scripts/codesign.sh b/.github/scripts/codesign.sh
new file mode 100755
index 00000000000000..076b29f93be45e
--- /dev/null
+++ b/.github/scripts/codesign.sh
@@ -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"
diff --git a/.github/scripts/notarize.sh b/.github/scripts/notarize.sh
new file mode 100755
index 00000000000000..9315d688afbd49
--- /dev/null
+++ b/.github/scripts/notarize.sh
@@ -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"
diff --git a/.github/scripts/run-esrp-signing.py b/.github/scripts/run-esrp-signing.py
deleted file mode 100644
index 725bf4580f5f1b..00000000000000
--- a/.github/scripts/run-esrp-signing.py
+++ /dev/null
@@ -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}")
\ No newline at end of file
diff --git a/.github/scripts/set-up-esrp.ps1 b/.github/scripts/set-up-esrp.ps1
deleted file mode 100644
index ca56266e33f553..00000000000000
--- a/.github/scripts/set-up-esrp.ps1
+++ /dev/null
@@ -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
\ No newline at end of file
diff --git a/.github/workflows/build-git-installers.yml b/.github/workflows/build-git-installers.yml
index 8ac2bef0e85efc..05c9e97b011355 100644
--- a/.github/workflows/build-git-installers.yml
+++ b/.github/workflows/build-git-installers.yml
@@ -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
- uses: actions/upload-artifact@v3
- with:
- name: tmp.osx-${{ matrix.arch.name }}-build
- path: |
- build_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"
- - name: Upload list of executable files
- uses: actions/upload-artifact@v3
- with:
- name: tmp.executable-files
- path: |
- executable-files.txt
+ # Create DMG
+ make -C git/.github/macos-installer V=1 image || die "Creating DMG failed"
- 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'
+ # Move all artifacts into top-level directory
+ mv git/.github/macos-installer/disk-image/*.pkg git/.github/macos-installer/
- - 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 &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
- uses: actions/download-artifact@v3
- with:
- name: osx-x86_64-dmg
- path: osx-dmg
- - name: Download Mac ARM64 dmg
- 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
+
+ - name: Download macOS artifacts
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'
+ name: macos-artifacts
+ path: macos-artifacts
+
+ - name: Download Debian package
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')
diff --git a/README.md b/README.md
index fe82df58415570..cb7be1a108914f 100644
--- a/README.md
+++ b/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
+# 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
+
+
+
+
+
+
+
+
+
+
+
+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,