8000 Fix various issues with build-git-installers.yml by mjcheetham · Pull Request #741 · microsoft/git · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Fix various issues with build-git-installers.yml #741

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Apr 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
2394117
fixup! .github/actions/akv-secret: add action to get secrets
dscho Apr 8, 2025
99d0945
fixup! .github/actions/akv-secret: add action to get secrets
dscho Apr 8, 2025
ad02e8f
fixup! .github/actions/akv-secret: add action to get secrets
mjcheetham Apr 8, 2025
c579c82
fixup! fixup! release: create initial Windows installer build workflow
dscho Apr 8, 2025
3d2c719
fixup! fixup! release: create initial Windows installer build workflow
dscho Apr 8, 2025
7c261dc
fixup! fixup! release: create initial Windows installer build workflow
mjcheetham Apr 8, 2025
cbb2a2e
fixup! fixup! release: create initial Windows installer build workflow
mjcheetham Apr 8, 2025
2719153
fixup! fixup! release: create initial Windows installer build workflow
mjcheetham Apr 8, 2025
db0542b
fixup! fixup! release: add Mac OSX installer build
dscho Apr 8, 2025
b76b666
fixup! fixup! release: add Mac OSX installer build
dscho Apr 8, 2025
4fe709d
fixup! fixup! release: add Mac OSX installer build
mjcheetham Apr 8, 2025
56dc3ef
fixup! fixup! release: add Mac OSX installer build
dscho Apr 8, 2025
26ecfb3
fixup! fixup! release: add Mac OSX installer build
mjcheetham Apr 8, 2025
5aee61e
fixup! fixup! release: add signing step for .deb package
dscho Apr 8, 2025
f9bc6c2
fixup! fixup! release: add signing step for .deb package
mjcheetham Apr 8, 2025
ca38143
fixup! fixup! build-git-installers: publish gpg public key
dscho Apr 8, 2025
e730d37
fixup! fixup! build-git-installers: publish gpg public key
mjcheetham Apr 8, 2025
6a7e382
fixup! .github/actions/akv-secret: add action to get secrets
mjcheetham Apr 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 95 additions & 35 deletions .github/actions/akv-secret/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const { spawnSync } = require('child_process');
const fs = require('fs');
const os = require('os');
const path = require('path');
const { isUtf8 } = require("buffer");

// Note that we are not using the `@actions/core` package as it is not available
// without either committing node_modules/ to the repository, or using something
Expand All @@ -14,6 +16,35 @@ const escapeData = (s) => {
.replace(/\n/g, '%0A')
}

const stringify = (value) => {
if (typeof value === 'string') return value;
if (Buffer.isBuffer(value) && isUtf8(value)) return value.toString('utf-8');
return undefined;
}

const trimEOL = (buf) => {
let l = buf.length
if (l > 0 && buf[l - 1] === 0x0a) {
l -= l > 1 && buf[l - 2] === 0x0d ? 2 : 1
}
return buf.slice(0, l)
}

const writeBufToFile = (buf, file) => {
out = fs.createWriteStream(file)
out.write(buf)
out.end()
}

const logInfo = (message) => {
process.stdout.write(`${message}${os.EOL}`);
}

const setFailed = (error) => {
process.stdout.write(`::error::${escapeData(error.message)}${os.EOL}`);
process.exitCode = 1;
}

const writeCommand = (file, name, value) => {
// Unique delimiter to avoid conflicts with actual values
let delim;
Expand All @@ -28,24 +59,38 @@ const writeCommand = (file, name, value) => {
}

const setSecret = (value) => {
process.stdout.write(`::add-mask::${escapeData(value)}${os.EOL}`);
value = stringify(value);

// Masking a secret that is not a valid UTF-8 string or buffer is not useful
if (value === undefined) return;

process.stdout.write(
value
.split(/\r?\n/g)
.filter(line => line.length > 0) // Cannot mask empty lines
.map(
value => `::add-mask::${escapeData(value)}${os.EOL}`
)
.join('')
);
}

const setOutput = (name, value) => {
value = stringify(value);
if (value === undefined) {
throw new Error(`Output value '${name}' is not a valid UTF-8 string or buffer`);
}

writeCommand(process.env.GITHUB_OUTPUT, name, value);
}

const exportVariable = (name, value) => {
writeCommand(process.env.GITHUB_ENV, name, value);
}

const logInfo = (message) => {
process.stdout.write(`${message}${os.EOL}`);
}
value = stringify(value);
if (value === undefined) {
throw new Error(`Environment variable '${name}' is not a valid UTF-8 string or buffer`);
}

const setFailed = (error) => {
process.stdout.write(`::error::${escapeData(error.message)}${os.EOL}`);
process.exitCode = 1;
writeCommand(process.env.GITHUB_ENV, name, value);
}

(async () => {
Expand All @@ -67,9 +112,7 @@ const setFailed = (error) => {

// Fetch secrets from Azure Key Vault
for (const { input: secretName, encoding, output } of secretMappings) {
let secretValue = '';

const az = spawnSync('az',
let az = spawnSync('az',
[
'keyvault',
'secret',
Expand All @@ -92,10 +135,12 @@ const setFailed = (error) => {
if (az.error) throw new Error(az.error, { cause: az.error });
if (az.status !== 0) throw new Error(`az failed with status ${az.status}`);

secretValue = az.stdout.toString('utf-8').trim();
// az keyvault secret show --output tsv returns a buffer with trailing \n
// (or \r\n on Windows), so we need to trim it specifically.
let secretBuf = trimEOL(az.stdout);

// Mask the raw secret value in logs
setSecret(secretValue);
setSecret(secretBuf);

// Handle encoded values if specified
// Sadly we cannot use the `--encoding` parameter of the `az keyvault
Expand All @@ -105,31 +150,46 @@ const setFailed = (error) => {
if (encoding) {
switch (encoding.toLowerCase()) {
case 'base64':
secretValue = Buffer.from(secretValue, 'base64').toString();
secretBuf = Buffer.from(secretBuf.toString('utf-8'), 'base64');
break;
case 'ascii':
case 'utf8':
case 'utf-8':
// No need to decode the existing buffer from the az command
break;
default:
// No decoding needed
}
throw new Error(`Unsupported encoding: ${encoding}`);
}

setSecret(secretValue); // Mask the decoded value as well
// Mask the decoded value
setSecret(secretBuf);
}

if (output.startsWith('$env:')) {
// Environment variable
const envVarName = output.replace('$env:', '').trim();
exportVariable(envVarName, secretValue);
logInfo(`Secret set as environment variable: ${envVarName}`);
} else if (output.startsWith('$output:')) {
// GitHub Actions output variable
const outputName = output.replace('$output:', '').trim();
setOutput(outputName, secretValue);
logInfo(`Secret set as output variable: ${outputName}`);
} else {
// File output
const filePath = output.trim();
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, secretValue);
logInfo(`Secret written to file: ${filePath}`);
const outputType = output.startsWith('$env:')
? 'env'
: output.startsWith('$output:')
? 'output'
: 'file';

switch (outputType) {
case 'env':
const varName = output.replace('$env:', '').trim();
exportVariable(varName, secretBuf);
logInfo(`Secret set as environment variable: ${varName}`);
break;

case 'output':
const outputName = output.replace('$output:', '').trim();
setOutput(outputName, secretBuf);
logInfo(`Secret set as output variable: ${outputName}`);
break;

case 'file':
const filePath = output.trim();
fs.mkdirSync(path.dirname(filePath), { recursive: true });
writeBufToFile(secretBuf, filePath);
logInfo(`Secret written to file: ${filePath}`);
break;
}
}
})().catch(setFailed);
76 changes: 57 additions & 19 deletions .github/workflows/build-git-installers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@ jobs:
with:
vault: ${{ secrets.AZURE_VAULT }}
secrets: |
${{ secrets.WIN_GPG_KEYGRIP_SECRET_NAME }} > $output:keygrip
${{ secrets.WIN_GPG_PRIVATE_SECRET_NAME }} > $output:private-key
${{ secrets.WIN_GPG_PASSPHRASE_SECRET_NAME }} > $output:passphrase
${{ secrets.WIN_GPG_KEYGRIP_SECRET_NAME }} > $output:keygrip
${{ secrets.WIN_GPG_PRIVATE_SECRET_NAME }} base64> $output:private-key
${{ secrets.WIN_GPG_PASSPHRASE_SECRET_NAME }} > $output:passphrase
- name: Prepare home directory for GPG signing
if: ${{ steps.gpg-secrets.outputs.keygrip != '' && steps.gpg-secrets.outputs.private-key != '' }}
shell: bash
Expand Down Expand Up @@ -218,10 +218,22 @@ jobs:
shell: bash
run: |
git clone --filter=blob:none --single-branch -b main https://github.com/git-for-windows/build-extra /usr/src/build-extra
- name: Log in to Azure
uses: azure/login@v2
if: env.DO_WIN_CODESIGN == 'true'
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Check out repository (for akv-secret Action)
if: env.DO_WIN_CODESIGN == 'true'
uses: actions/checkout@v4
with:
path: git
- name: Download code signing secrets
id: codesign-secrets
if: env.DO_WIN_CODESIGN == 'true'
uses: ./.github/actions/akv-secret
uses: ./git/.github/actions/akv-secret
with:
vault: ${{ secrets.AZURE_VAULT }}
secrets: |
Expand Down Expand Up @@ -344,13 +356,22 @@ jobs:
fi &&
openssl dgst -sha256 artifacts/${{matrix.type.fileprefix}}-*.exe | sed "s/.* //" >artifacts/sha-256.txt
- name: Verify that .exe files are code-signed
env:
DO_CODE_SIGN: ${{ secrets.WIN_CODESIGN_CERT_SECRET_NAME != '' }}
if: env.DO_CODE_SIGN == 'true'
shell: bash
if: env.DO_WIN_CODESIGN == 'true'
shell: pwsh
run: |
< 5DA8 span class='blob-code-inner blob-code-marker js-skip-tagsearch' data-code-marker="-"> PATH=$PATH:"/c/Program Files (x86)/Windows Kits/10/App Certification Kit/" \
signtool verify //pa artifacts/${{matrix.type.fileprefix}}-*.exe
$ret = 0
$files = Get-ChildItem -Path artifacts -Filter "${{matrix.type.fileprefix}}-*.exe"
foreach ($file in $files) {
$signature = Get-AuthenticodeSignature -FilePath $file.FullName
if ($signature.Status -eq 'Valid') {
Write-Host "[ VALID ] $($file.FullName)"
} else {
Write-Host "[INVALID] $($file.FullName)"
Write-Host " Message: $($signature.StatusMessage)"
$ret = 1
}
}
exit $ret
- name: Publish ${{matrix.type.name}}-${{matrix.arch.name}}
uses: actions/upload-artifact@v4
with:
Expand All @@ -369,7 +390,7 @@ jobs:
- name: Check out repository
uses: actions/checkout@v4
with:
path: 'git'
path: git

- name: Install Git dependencies
run: |
Expand All @@ -386,9 +407,16 @@ jobs:
# Make universal gettext library
lipo -create -output libintl.a /usr/local/opt/gettext/lib/libintl.a /opt/homebrew/opt/gettext/lib/libintl.a

- name: Log in to Azure
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Download signing secrets
id: signing-secrets
uses: ./.github/actions/akv-secret
uses: ./git/.github/actions/akv-secret
with:
vault: ${{ secrets.AZURE_VAULT }}
secrets: |
Expand All @@ -399,8 +427,8 @@ jobs:
${{ secrets.APPLE_DEVELOPER_PASSWORD_SECRET_NAME }} > $output:dev-pass
${{ secrets.APPLE_APPCERT_PASS_SECRET_NAME }} > $output:appcert-pass
${{ secrets.APPLE_INSTCERT_PASS_SECRET_NAME }} > $output:instcert-pass
${{ secrets.APPLE_APPCERT_SECRET_NAME }} base64> appcert.p12
${{ secrets.APPLE_INSTCERT_SECRET_NAME }} base64> instcert.p12
${{ secrets.APPLE_APPCERT_SECRET_NAME }} base64> ${{ runner.temp }}/appcert.p12
${{ secrets.APPLE_INSTCERT_SECRET_NAME }} base64> ${{ runner.temp }}/instcert.p12

- name: Set up signing/notarization infrastructure
run: |
Expand All @@ -411,7 +439,7 @@ jobs:
# Prevent re-locking
security set-keychain-settings $RUNNER_TEMP/buildagent.keychain

security import appcert.p12 \
security import $RUNNER_TEMP/appcert.p12 \
-k $RUNNER_TEMP/buildagent.keychain \
-P '${{ steps.signing-secrets.outputs.appcert-pass }}' \
-T /usr/bin/codesign
Expand All @@ -420,7 +448,7 @@ jobs:
-s -k pwd \
$RUNNER_TEMP/buildagent.keychain

security import instcert.p12 \
security import $RUNNER_TEMP/instcert.p12 \
-k $RUNNER_TEMP/buildagent.keychain \
-P '${{ steps.signing-secrets.outputs.instcert-pass }}' \
-T /usr/bin/pkgbuild
Expand Down Expand Up @@ -496,7 +524,7 @@ jobs:
cp -R stage/git-universal-$VERSION/ \
git/.github/macos-installer/build-artifacts
make -C git/.github/macos-installer V=1 codesign \
APPLE_APP_IDENTITY=${{ steps.signing-secrets.outputs.appsign-id }} || die "Creating signed payload failed"
APPLE_APP_IDENTITY='${{ steps.signing-secrets.outputs.appsign-id }}' || die "Creating signed payload failed"

# Build and sign pkg
make -C git/.github/macos-installer V=1 pkg \
Expand Down Expand Up @@ -636,9 +664,14 @@ jobs:
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- 93A9 name: Check out repository (for akv-secret Action)
uses: actions/checkout@v4
with:
path: git

- name: Download GPG secrets
id: gpg-secrets
uses: ./.github/actions/akv-secret
uses: ./git/.github/actions/akv-secret
with:
vault: ${{ secrets.AZURE_VAULT }}
secrets: |
Expand Down Expand Up @@ -809,8 +842,13 @@ jobs:
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Check out repository (for akv-secret Action)
uses: actions/checkout@v4
with:
path: git

- name: Download Linux GPG public key signature file
uses: ./.github/actions/akv-secret
uses: ./git/.github/actions/akv-secret
with:
vault: ${{ secrets.AZURE_VAULT }}
secrets: |
Expand Down
Loading
0