Build fleetctl MSI packages (#43403)

This commit is contained in:
Scott Gress
2026-04-29 17:09:19 -05:00
committed by GitHub
parent cdd134af7b
commit 07b6679ead
5 changed files with 606 additions and 0 deletions
+204
View File
@@ -0,0 +1,204 @@
name: Build fleetctl Windows MSI
# This workflow builds a signed Windows .msi installer for fleetctl
# for manual testing purposes only.
#
# NOTE: For production releases, the goreleaser workflow (.github/workflows/goreleaser-fleet.yaml)
# handles building and uploading the fleetctl MSI automatically when a fleet-* tag is pushed.
# This workflow is kept for manual testing only.
#
# TESTING:
# To test the MSI build process:
# 1. Go to Actions -> Build fleetctl Windows MSI -> Run workflow
# 2. Select your branch (e.g., main or feature branch)
# 3. Test mode defaults to true (recommended) - MSI will be built and uploaded as an artifact
# 4. To test release upload, set test_mode to false (use with caution)
on:
workflow_dispatch: # Manual trigger for testing only
inputs:
test_mode:
description: "Test mode - will skip release upload if enabled (recommended: true)"
type: boolean
default: true
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
# fail-fast using bash -eo pipefail. See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#exit-codes-and-error-action-preference
shell: bash
permissions:
contents: write # Needed to upload release assets
id-token: write # Needed for attestations
attestations: write # Needed to create build provenance attestations
jobs:
build-sign-msi:
runs-on: windows-2022
timeout-minutes: 60
strategy:
matrix:
arch: [amd64, arm64]
steps:
- name: Harden Runner
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
with:
egress-policy: audit
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
with:
fetch-depth: 0
- name: Extract version
id: extract_version
run: |
REF_NAME="${{ github.ref_name }}"
# Check if running from a tag
if [[ "${{ github.ref }}" == refs/tags/* ]] && [[ "$REF_NAME" == fleet-* ]]; then
VERSION="${REF_NAME#fleet-}"
VERSION="${VERSION#v}"
TAG_NAME="$REF_NAME"
else
VERSION="test-$(date +%Y%m%d-%H%M%S)"
TAG_NAME="fleet-${VERSION}"
fi
# For MSI, we need a numeric version (X.Y.Z). Use 0.0.0 for test builds.
if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
MSI_VERSION="$VERSION"
else
MSI_VERSION="0.0.0"
fi
# Determine test mode
if [ "${{ github.event.inputs.test_mode }}" = "false" ]; then
IS_TEST_MODE="false"
else
IS_TEST_MODE="true"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "msi_version=$MSI_VERSION" >> $GITHUB_OUTPUT
echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT
echo "is_test_mode=$IS_TEST_MODE" >> $GITHUB_OUTPUT
echo "Fleet version: $VERSION (MSI version: $MSI_VERSION)"
if [ "$IS_TEST_MODE" = "true" ]; then
echo "TEST MODE: MSI will be built but NOT uploaded to release"
else
echo "PRODUCTION MODE: MSI will be uploaded to release $TAG_NAME"
fi
- name: Set up Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
with:
go-version-file: "go.mod"
- name: Build fleetctl binary
run: |
VERSION="${{ steps.extract_version.outputs.version }}"
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
BRANCH_NAME="${{ steps.extract_version.outputs.tag_name }}"
else
BRANCH_NAME="${GITHUB_REF#refs/heads/}"
fi
LDFLAGS="-X github.com/fleetdm/fleet/v4/server/version.appName=fleetctl \
-X github.com/fleetdm/fleet/v4/server/version.version=${VERSION} \
-X github.com/fleetdm/fleet/v4/server/version.branch=${BRANCH_NAME} \
-X github.com/fleetdm/fleet/v4/server/version.revision=${GITHUB_SHA} \
-X github.com/fleetdm/fleet/v4/server/version.buildDate=$(date -u +%Y-%m-%d) \
-X github.com/fleetdm/fleet/v4/server/version.buildUser=github-actions"
echo "Building fleetctl for windows/${{ matrix.arch }}..."
CGO_ENABLED=0 GOOS=windows GOARCH=${{ matrix.arch }} go build \
-trimpath \
-ldflags "$LDFLAGS" \
-o fleetctl.exe \
./cmd/fleetctl
if [ ! -f fleetctl.exe ]; then
echo "Error: fleetctl.exe not found after build"
exit 1
fi
echo "Built fleetctl.exe ($(wc -c < fleetctl.exe) bytes)"
- name: Install WiX 3.14.1
run: |
curl -fSL -o wix314-binaries.zip \
https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip
mkdir -p "$RUNNER_TEMP/wix"
unzip -q wix314-binaries.zip -d "$RUNNER_TEMP/wix"
echo "$RUNNER_TEMP/wix" >> $GITHUB_PATH
- name: Setup DigiCert KeyLocker
env:
DIGICERT_KEYLOCKER_CERTIFICATE: ${{ secrets.DIGICERT_KEYLOCKER_CERTIFICATE }}
DIGICERT_KEYLOCKER_PASSWORD: ${{ secrets.DIGICERT_KEYLOCKER_PASSWORD }}
DIGICERT_KEYLOCKER_HOST_URL: ${{ secrets.DIGICERT_KEYLOCKER_HOST_URL }}
DIGICERT_API_KEY: ${{ secrets.DIGICERT_API_KEY }}
run: |
# Decode certificate
echo "$DIGICERT_KEYLOCKER_CERTIFICATE" | base64 --decode > /d/Certificate_pkcs12.p12
# Set environment variables for subsequent steps
echo "SM_HOST=$DIGICERT_KEYLOCKER_HOST_URL" >> "$GITHUB_ENV"
echo "SM_API_KEY=$DIGICERT_API_KEY" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_PASSWORD=$DIGICERT_KEYLOCKER_PASSWORD" >> "$GITHUB_ENV"
# Add signing tools to PATH
echo "C:\Program Files (x86)\Windows Kits\10\App Certification Kit" >> $GITHUB_PATH
echo "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools" >> $GITHUB_PATH
echo "C:\Program Files\DigiCert\DigiCert Keylocker Tools" >> $GITHUB_PATH
- name: Install DigiCert KeyLocker KSP
run: |
curl https://one.digicert.com/signingmanager/api-ui/v1/releases/Keylockertools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" --fail-with-body -o Keylockertools-windows-x64.msi
msiexec /i Keylockertools-windows-x64.msi /quiet /qn
smksp_registrar.exe list
smctl.exe keypair ls
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
shell: cmd
- name: Sync certificates
run: |
smctl windows certsync
shell: cmd
- name: Build and sign MSI
env:
DIGICERT_KEYLOCKER_CERTIFICATE_FINGERPRINT: ${{ secrets.DIGICERT_KEYLOCKER_CERTIFICATE_FINGERPRINT }}
SKIP_UPLOAD: ${{ inputs.test_mode && 'true' || 'false' }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_REF: ${{ github.ref }}
run: |
chmod +x tools/build-fleetctl-msi/main.sh
./tools/build-fleetctl-msi/main.sh \
fleetctl.exe \
"${{ steps.extract_version.outputs.msi_version }}" \
"${{ matrix.arch }}"
- name: Upload MSI artifact (test mode)
if: ${{ inputs.test_mode }}
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: fleetctl-msi-${{ matrix.arch }}
path: dist/fleetctl_v${{ steps.extract_version.outputs.msi_version }}_windows_${{ matrix.arch }}.msi
retention-days: 7
- name: Attest MSI
continue-on-error: true
uses: actions/attest-build-provenance@619dbb2e03e0189af0c55118e7d3c5e129e99726 # v2.0
with:
subject-path: dist/fleetctl_v${{ steps.extract_version.outputs.msi_version }}_windows_${{ matrix.arch }}.msi
push-to-registry: false
+186
View File
@@ -22,6 +22,8 @@ jobs:
goreleaser:
runs-on: ubuntu-22.04-4-cores
environment: Docker Hub
outputs:
windows_msi_arches: ${{ steps.check_windows_binaries.outputs.arches }}
permissions:
contents: write
id-token: write
@@ -156,3 +158,187 @@ jobs:
docker tag fleetdm/fleet:${TAG} quay.io/fleetdm/fleet:${TAG}
docker push quay.io/fleetdm/fleet:${TAG}
done
- name: Check if Windows fleetctl binaries exist
id: check_windows_binaries
continue-on-error: true
run: |
# Goreleaser v2 places binaries at dist/<id>_<os>_<arch>*/binary
ARCHES=()
for arch in amd64 arm64; do
EXE=$(find dist -name "fleetctl.exe" -path "*windows*${arch}*" -print -quit 2>/dev/null)
if [[ -n "$EXE" ]]; then
echo "Found: $EXE"
echo "windows_${arch}_path=$EXE" >> "$GITHUB_OUTPUT"
ARCHES+=("\"$arch\"")
else
echo "Warning: No fleetctl.exe found for windows/$arch"
fi
done
echo "arches=[$(IFS=,; echo "${ARCHES[*]}")]" >> "$GITHUB_OUTPUT"
- name: Upload unsigned Windows fleetctl amd64
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
if: steps.check_windows_binaries.outputs.windows_amd64_path != ''
with:
name: fleetctl-unsigned-windows-amd64
path: ${{ steps.check_windows_binaries.outputs.windows_amd64_path }}
retention-days: 1
- name: Upload unsigned Windows fleetctl arm64
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
if: steps.check_windows_binaries.outputs.windows_arm64_path != ''
with:
name: fleetctl-unsigned-windows-arm64
path: ${{ steps.check_windows_binaries.outputs.windows_arm64_path }}
retention-days: 1
build-fleetctl-msi:
runs-on: windows-2022
needs: goreleaser
if: needs.goreleaser.outputs.windows_msi_arches != '[]'
timeout-minutes: 60
strategy:
matrix:
arch: ${{ fromJSON(needs.goreleaser.outputs.windows_msi_arches) }}
permissions:
contents: write
id-token: write
attestations: write
steps:
- name: Harden Runner
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
with:
egress-policy: audit
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- name: Download unsigned fleetctl binary
uses: actions/download-artifact@9c19ed7fe5d278cd354c7dfd5d3b88589c7e2395 # v4.1.8
with:
name: fleetctl-unsigned-windows-${{ matrix.arch }}
- name: Verify binary exists
run: |
if [[ ! -f "fleetctl.exe" ]]; then
echo "Error: fleetctl.exe not found after download"
ls -la
exit 1
fi
echo "Binary found ($(wc -c < fleetctl.exe) bytes)"
- name: Extract version from tag
id: version
run: |
TAG_NAME="${{ github.ref_name }}"
VERSION="${TAG_NAME#fleet-}"
VERSION="${VERSION#v}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Version: $VERSION"
- name: Install WiX 3.14.1
run: |
curl -fSL -o wix314-binaries.zip \
https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip
mkdir -p "$RUNNER_TEMP/wix"
unzip -q wix314-binaries.zip -d "$RUNNER_TEMP/wix"
echo "$RUNNER_TEMP/wix" >> $GITHUB_PATH
- name: Setup DigiCert KeyLocker
env:
DIGICERT_KEYLOCKER_CERTIFICATE: ${{ secrets.DIGICERT_KEYLOCKER_CERTIFICATE }}
DIGICERT_KEYLOCKER_PASSWORD: ${{ secrets.DIGICERT_KEYLOCKER_PASSWORD }}
DIGICERT_KEYLOCKER_HOST_URL: ${{ secrets.DIGICERT_KEYLOCKER_HOST_URL }}
DIGICERT_API_KEY: ${{ secrets.DIGICERT_API_KEY }}
run: |
echo "$DIGICERT_KEYLOCKER_CERTIFICATE" | base64 --decode > /d/Certificate_pkcs12.p12
echo "SM_HOST=$DIGICERT_KEYLOCKER_HOST_URL" >> "$GITHUB_ENV"
echo "SM_API_KEY=$DIGICERT_API_KEY" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_PASSWORD=$DIGICERT_KEYLOCKER_PASSWORD" >> "$GITHUB_ENV"
echo "C:\Program Files (x86)\Windows Kits\10\App Certification Kit" >> $GITHUB_PATH
echo "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools" >> $GITHUB_PATH
echo "C:\Program Files\DigiCert\DigiCert Keylocker Tools" >> $GITHUB_PATH
- name: Install DigiCert KeyLocker KSP
run: |
curl https://one.digicert.com/signingmanager/api-ui/v1/releases/Keylockertools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" --fail-with-body -o Keylockertools-windows-x64.msi
msiexec /i Keylockertools-windows-x64.msi /quiet /qn
smksp_registrar.exe list
smctl.exe keypair ls
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
shell: cmd
- name: Sync certificates
run: |
smctl windows certsync
shell: cmd
- name: Build and sign MSI
env:
DIGICERT_KEYLOCKER_CERTIFICATE_FINGERPRINT: ${{ secrets.DIGICERT_KEYLOCKER_CERTIFICATE_FINGERPRINT }}
SKIP_UPLOAD: "true"
run: |
chmod +x tools/build-fleetctl-msi/main.sh
./tools/build-fleetctl-msi/main.sh \
fleetctl.exe \
"${{ steps.version.outputs.version }}" \
"${{ matrix.arch }}"
- name: Upload signed MSI artifact
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: fleetctl-msi-${{ matrix.arch }}
path: dist/fleetctl_v${{ steps.version.outputs.version }}_windows_${{ matrix.arch }}.msi
retention-days: 1
- name: Attest MSI
continue-on-error: true
uses: actions/attest-build-provenance@619dbb2e03e0189af0c55118e7d3c5e129e99726 # v2.0
with:
subject-path: dist/fleetctl_v${{ steps.version.outputs.version }}_windows_${{ matrix.arch }}.msi
upload-fleetctl-msi:
needs: build-fleetctl-msi
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Harden Runner
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
with:
egress-policy: audit
- name: Download signed MSI artifacts
uses: actions/download-artifact@9c19ed7fe5d278cd354c7dfd5d3b88589c7e2395 # v4.1.8
with:
pattern: fleetctl-msi-*
merge-multiple: true
path: dist
- name: Upload MSIs to release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG_NAME="${{ github.ref_name }}"
echo "Uploading MSIs to release $TAG_NAME..."
# Wait for release to exist
MAX_WAIT=300
ELAPSED=0
while [ $ELAPSED -lt $MAX_WAIT ]; do
if gh release view "$TAG_NAME" --repo "$GITHUB_REPOSITORY" &>/dev/null; then
echo "Release found"
break
fi
echo "Waiting for release... (${ELAPSED}s/${MAX_WAIT}s)"
sleep 10
ELAPSED=$((ELAPSED + 10))
done
for msi in dist/*.msi; do
echo "Uploading $msi..."
gh release upload "$TAG_NAME" "$msi" --repo "$GITHUB_REPOSITORY" --clobber
done
echo "Upload complete"
@@ -0,0 +1 @@
- `fleetctl` is now also released as an `msi` for Windows
+52
View File
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product
Id="*"
Name="fleetctl"
Language="1033"
Version="__VERSION__"
Manufacturer="Fleet Device Management (fleetdm.com)"
UpgradeCode="DA27C96F-3832-4E04-A6A9-1FDE1A8B37BE">
<Package
Keywords="fleetctl"
Description="Fleet device management CLI tool"
InstallerVersion="500"
Compressed="yes"
InstallScope="perMachine"
InstallPrivileges="elevated"
Languages="1033" />
<MediaTemplate EmbedCab="yes" />
<MajorUpgrade
DowngradeErrorMessage="A newer version of fleetctl is already installed."
AllowSameVersionUpgrades="yes" />
<Property Id="ARPNOREPAIR" Value="yes" Secure="yes" />
<Property Id="ARPNOMODIFY" Value="yes" Secure="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="FLEETDMDIR" Name="FleetDM">
<Directory Id="INSTALLDIR" Name="fleetctl">
<Component Id="C_FleetctlExe" Guid="E8A1B2C3-D4E5-6F78-9A0B-1C2D3E4F5A6B">
<File Id="FleetctlExe" Source="root\fleetctl.exe" KeyPath="yes" />
<Environment Id="PATH"
Name="PATH"
Value="[INSTALLDIR]"
Permanent="no"
Part="last"
Action="set"
System="yes" />
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
<Feature Id="FleetctlFeature" Title="fleetctl" Level="1">
<ComponentRef Id="C_FleetctlExe" />
</Feature>
</Product>
</Wix>
+163
View File
@@ -0,0 +1,163 @@
#!/usr/bin/env bash
set -eo pipefail
# This script builds a signed Windows .msi installer for fleetctl.
# It expects to run on a Windows GitHub Actions runner with Git Bash,
# with DigiCert KeyLocker already configured (env vars set, KSP installed,
# certs synced) and WiX 3.14 tools on PATH.
#
# Usage: ./main.sh <path-to-fleetctl.exe> <version> <arch>
# version: semver like "4.72.0" or "v4.72.0" (v prefix stripped)
# arch: "amd64" or "arm64"
#
# Environment variables:
# DIGICERT_KEYLOCKER_CERTIFICATE_FINGERPRINT - SHA1 fingerprint for signtool
# SKIP_UPLOAD - set to "true" to skip GitHub release upload (default: skip)
# GITHUB_TOKEN, GITHUB_REPOSITORY, GITHUB_REF - required if uploading to release
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
check_env_var() {
if [[ -z "${!1}" ]]; then
echo "Error: Environment variable $1 not set."
exit 1
fi
}
# Parse arguments
FLEETCTL_EXE="$1"
VERSION="$2"
ARCH="${3:-amd64}"
if [[ -z "$FLEETCTL_EXE" ]] || [[ -z "$VERSION" ]]; then
echo "Usage: $0 <path-to-fleetctl.exe> <version> [arch]"
echo " version: semver like 4.72.0 or v4.72.0"
echo " arch: amd64 (default) or arm64"
exit 1
fi
if [[ ! -f "$FLEETCTL_EXE" ]]; then
echo "Error: fleetctl.exe not found at $FLEETCTL_EXE"
exit 1
fi
# Check required env var for signing
check_env_var "DIGICERT_KEYLOCKER_CERTIFICATE_FINGERPRINT"
# Strip v prefix from version
VERSION="${VERSION#v}"
# Validate version format (WiX requires X.Y.Z or X.Y.Z.W, each component 0-65535)
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]; then
echo "Error: Version '$VERSION' is not a valid MSI version (expected X.Y.Z or X.Y.Z.W)"
exit 1
fi
# Map Go arch to WiX candle arch
case "$ARCH" in
amd64) WIX_ARCH="x64" ;;
arm64) WIX_ARCH="arm64" ;;
*)
echo "Error: Unsupported architecture '$ARCH' (expected amd64 or arm64)"
exit 1
;;
esac
MSI_NAME="fleetctl_v${VERSION}_windows_${ARCH}.msi"
echo "Building $MSI_NAME..."
# Create working directory
WORKDIR="$(mktemp -d)"
# Convert to Windows path for native Windows tools (signtool, candle, light)
WORKDIR_WIN="$(cygpath -w "$WORKDIR")"
cleanup() {
echo "Cleaning up..."
rm -rf "$WORKDIR"
}
trap cleanup EXIT
# Set up working directory structure
mkdir -p "$WORKDIR/root"
cp "$FLEETCTL_EXE" "$WORKDIR/root/fleetctl.exe"
# Substitute version placeholder in WiX template
sed "s/__VERSION__/$VERSION/g" "$SCRIPT_DIR/fleetctl.wxs" > "$WORKDIR/main.wxs"
# Sign fleetctl.exe before packaging into MSI
# MSYS_NO_PATHCONV=1 prevents Git Bash from converting /flags to Windows paths
# Windows-native tools need Windows-style paths (WORKDIR_WIN)
echo "Signing fleetctl.exe..."
MSYS_NO_PATHCONV=1 signtool.exe sign /v /sha1 "$DIGICERT_KEYLOCKER_CERTIFICATE_FINGERPRINT" \
/tr http://timestamp.digicert.com /td SHA256 /fd SHA256 \
/d "fleetctl by Fleet Device Management" /du "https://fleetdm.com" \
"$WORKDIR_WIN\\root\\fleetctl.exe"
MSYS_NO_PATHCONV=1 signtool.exe verify /v /pa "$WORKDIR_WIN\\root\\fleetctl.exe"
echo "fleetctl.exe signed successfully"
# Compile WiX source
echo "Running candle (WiX compiler)..."
candle.exe "$WORKDIR_WIN\\main.wxs" -arch "$WIX_ARCH" -out "$WORKDIR_WIN\\main.wixobj"
# Link to create MSI
echo "Running light (WiX linker)..."
light.exe "$WORKDIR_WIN\\main.wixobj" -b "$WORKDIR_WIN" -out "$WORKDIR_WIN\\$MSI_NAME" -sval
# Sign the MSI
echo "Signing MSI..."
MSYS_NO_PATHCONV=1 signtool.exe sign /v /sha1 "$DIGICERT_KEYLOCKER_CERTIFICATE_FINGERPRINT" \
/tr http://timestamp.digicert.com /td SHA256 /fd SHA256 \
/d "fleetctl by Fleet Device Management" /du "https://fleetdm.com" \
"$WORKDIR_WIN\\$MSI_NAME"
MSYS_NO_PATHCONV=1 signtool.exe verify /v /pa "$WORKDIR_WIN\\$MSI_NAME"
echo "MSI signed successfully"
# Copy to output location
mkdir -p dist
cp "$WORKDIR/$MSI_NAME" "dist/$MSI_NAME"
echo "Package created: dist/$MSI_NAME"
# Upload to release unless skipped
if [[ "$SKIP_UPLOAD" == "true" ]]; then
echo "Skipping release upload (SKIP_UPLOAD=true)"
elif [[ -n "$GITHUB_TOKEN" ]] && [[ -n "$GITHUB_REPOSITORY" ]] && [[ -n "$GITHUB_REF" ]] && command -v gh &> /dev/null; then
if [[ "$GITHUB_REF" != refs/tags/* ]]; then
echo "Error: GITHUB_REF is not a tag ref ($GITHUB_REF), cannot upload to release"
exit 1
fi
TAG_NAME="${GITHUB_REF#refs/tags/}"
echo "Uploading package to release $TAG_NAME..."
# Wait for release to exist (goreleaser creates it as draft)
MAX_WAIT=300
ELAPSED=0
INTERVAL=10
while [ $ELAPSED -lt $MAX_WAIT ]; do
if gh release view "$TAG_NAME" --repo "$GITHUB_REPOSITORY" &>/dev/null; then
echo "Release found, uploading package..."
break
fi
echo "Waiting for release to be created... (${ELAPSED}s/${MAX_WAIT}s)"
sleep $INTERVAL
ELAPSED=$((ELAPSED + INTERVAL))
done
if [ $ELAPSED -ge $MAX_WAIT ]; then
echo "Warning: Release not found after waiting ${MAX_WAIT}s"
echo "Attempting upload anyway..."
fi
echo "Uploading dist/$MSI_NAME to release $TAG_NAME"
gh release upload "$TAG_NAME" "dist/$MSI_NAME" --repo "$GITHUB_REPOSITORY" --clobber || {
echo "Upload failed, retrying once..."
sleep 5
gh release upload "$TAG_NAME" "dist/$MSI_NAME" --repo "$GITHUB_REPOSITORY" --clobber || {
echo "Failed to upload package after retry"
exit 1
}
}
echo "Package uploaded successfully: dist/$MSI_NAME"
else
echo "Skipping release upload (GITHUB_TOKEN or gh not available)"
fi