Files
probo/.github/workflows/release-probo-agent.yaml
Ludovic Vielle 5e63e193cd Stop macOS agent updates from spawning BTM entries
Unsigned darwin release tarballs replaced the Developer ID
binary on each auto-update, so Background Task Management
treated every release as a new identity and showed the generic
executable icon. Sign those archives with a stable identifier,
refuse signature downgrades, and attribute daemon/tray jobs to
Probo Agent.app via AssociatedBundleIdentifiers.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-30 11:43:02 +02:00

279 lines
11 KiB
YAML

name: "Release probo-agent"
on:
push:
tags:
- "probo-agent/v*"
permissions:
contents: "read"
jobs:
build-binary:
name: "binary (${{ matrix.goos }}/${{ matrix.goarch }})"
runs-on: "runs-on=${{ github.run_id }}/runner=4cpu-linux-x64/extras=s3-cache"
permissions:
contents: "read"
strategy:
fail-fast: false
matrix:
include:
- { goos: linux, goarch: amd64 }
- { goos: linux, goarch: arm64 }
- { goos: windows, goarch: amd64 }
- { goos: windows, goarch: arm64 }
- { goos: freebsd, goarch: amd64 }
- { goos: freebsd, goarch: arm64 }
steps:
- uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v6
with:
submodules: recursive
- uses: "runs-on/action@d141ef83eb66d096ce8afc767e09115a65c63b60" # v2
- uses: "./.github/actions/setup"
with:
node: "false"
- name: "Build binary"
env:
CGO_ENABLED: "0"
GOOS: "${{ matrix.goos }}"
GOARCH: "${{ matrix.goarch }}"
run: |
VERSION="${GITHUB_REF_NAME##*/v}"
EXT=""
if [ "$GOOS" = "windows" ]; then EXT=".exe"; fi
go build -ldflags "-s -w -X 'main.version=${VERSION}'" \
-gcflags="-e" -o "dist/probo-agent${EXT}" ./cmd/probo-agent
- name: "Create archive"
env:
GOOS: "${{ matrix.goos }}"
GOARCH: "${{ matrix.goarch }}"
run: |
case "$GOOS" in
linux) OS="Linux" ;;
windows) OS="Windows" ;;
freebsd) OS="Freebsd" ;;
esac
case "$GOARCH" in
amd64) ARCH="x86_64" ;;
*) ARCH="$GOARCH" ;;
esac
EXT=""
if [ "$GOOS" = "windows" ]; then EXT=".exe"; fi
mkdir -p archives
AGENT_DIR="probo-agent_${OS}_${ARCH}"
mkdir -p "staging/${AGENT_DIR}"
cp "dist/probo-agent${EXT}" README.md LICENSE "staging/${AGENT_DIR}/"
if [ -f cmd/probo-agent/CHANGELOG.md ]; then
cp cmd/probo-agent/CHANGELOG.md "staging/${AGENT_DIR}/"
fi
if [ "$GOOS" = "windows" ]; then
(cd staging && zip -r "../archives/${AGENT_DIR}.zip" "${AGENT_DIR}")
else
tar -czf "archives/${AGENT_DIR}.tar.gz" -C staging "${AGENT_DIR}"
fi
- uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7
with:
name: "archive-${{ matrix.goos }}-${{ matrix.goarch }}"
path: "archives/"
retention-days: 1
build-macos:
name: "macos (darwin pkg + darwin archives)"
runs-on: "macos-26"
permissions:
contents: "read"
steps:
- uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v6
with:
submodules: recursive
- uses: "./.github/actions/setup"
with:
node: "false"
- name: "Select Xcode version"
run: |
sudo xcode-select -s /Applications/Xcode_26.2.app/Contents/Developer
xcode-select -p
swift --version
- name: "Import signing certificate"
env:
CERTIFICATE_BASE64: "${{ secrets.APPLE_CERTIFICATE }}"
CERTIFICATE_PASSWORD: "${{ secrets.APPLE_CERTIFICATE_PASSWORD }}"
KEYCHAIN_PASSWORD: "${{ secrets.KEYCHAIN_PASSWORD }}"
run: |
KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db"
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
echo "$CERTIFICATE_BASE64" | base64 --decode > certificate.p12
security import certificate.p12 -P "$CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security list-keychain -d user -s "$KEYCHAIN_PATH"
rm certificate.p12
- name: "Build CGO darwin binaries and darwin pkg"
env:
CGO_ENABLED: "1"
CODESIGN_IDENTITY: "${{ secrets.CODESIGN_IDENTITY }}"
INSTALLER_IDENTITY: "${{ secrets.INSTALLER_IDENTITY }}"
APPLE_ID: "${{ secrets.APPLE_ID }}"
APPLE_ID_PASSWORD: "${{ secrets.APPLE_ID_PASSWORD }}"
APPLE_TEAM_ID: "${{ secrets.APPLE_TEAM_ID }}"
run: |
set -euo pipefail
VERSION="${GITHUB_REF_NAME##*/v}"
LDFLAGS="-s -w -X 'main.version=${VERSION}'"
mkdir -p dist archives staging
export COPYFILE_DISABLE=1
GOOS=darwin GOARCH=arm64 go build -ldflags "${LDFLAGS}" \
-gcflags="-e" -o dist/probo-agent_arm64 ./cmd/probo-agent
GOOS=darwin GOARCH=amd64 go build -ldflags "${LDFLAGS}" \
-gcflags="-e" -o dist/probo-agent_amd64 ./cmd/probo-agent
lipo -create \
dist/probo-agent_arm64 \
dist/probo-agent_amd64 \
-output dist/probo-agent_universal
for pair in "arm64:arm64" "amd64:x86_64"; do
GOARCH="${pair%%:*}"
ARCH="${pair##*:}"
AGENT_DIR="probo-agent_Darwin_${ARCH}"
mkdir -p "staging/${AGENT_DIR}"
cp "dist/probo-agent_${GOARCH}" "staging/${AGENT_DIR}/probo-agent"
cp README.md LICENSE "staging/${AGENT_DIR}/"
if [ -f cmd/probo-agent/CHANGELOG.md ]; then
cp cmd/probo-agent/CHANGELOG.md "staging/${AGENT_DIR}/"
fi
# Match the PKG payload signing identity so auto-update does
# not replace a Developer ID binary with an ad-hoc one (which
# multiplies macOS Background Activity entries).
codesign --force --options runtime --timestamp \
--identifier com.probo.agent \
--sign "${CODESIGN_IDENTITY}" "staging/${AGENT_DIR}/probo-agent"
codesign --verify --verbose=2 "staging/${AGENT_DIR}/probo-agent"
tar -czf "archives/${AGENT_DIR}.tar.gz" -C staging "${AGENT_DIR}"
done
chmod +x cmd/probo-agent/installer/macos/build.sh \
cmd/probo-agent/installer/macos/scripts/preinstall \
cmd/probo-agent/installer/macos/scripts/postinstall
cmd/probo-agent/installer/macos/build.sh \
--binary dist/probo-agent_universal \
--version "${VERSION}" \
--output "archives/probo-agent_${VERSION}_darwin.pkg"
- uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7
with:
name: "archive-darwin"
path: "archives/"
retention-days: 1
github-release:
name: "github-release"
needs: [build-binary, build-macos]
runs-on: "runs-on=${{ github.run_id }}/runner=2cpu-linux-x64/extras=s3-cache"
permissions:
contents: "write"
id-token: "write"
attestations: "write"
steps:
- uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v6
with:
fetch-depth: 0
- uses: "runs-on/action@d141ef83eb66d096ce8afc767e09115a65c63b60" # v2
- uses: "sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6" # v4.1.2
- uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8
with:
pattern: "archive-*"
path: "archives"
merge-multiple: true
- name: "Generate checksums and sign"
run: |
cd archives
sha256sum *.tar.gz *.zip *.pkg > checksums.txt
cosign sign-blob --bundle="checksums.txt.bundle" checksums.txt --yes
- name: "Inject release checksums into install.sh"
run: |
TAG="${GITHUB_REF_NAME}"
cp cmd/probo-agent/installer/install.sh archives/install.sh
sed -i "s|^RELEASE_TAG=\"__PROBO_AGENT_RELEASE_TAG__\"|RELEASE_TAG=\"${TAG}\"|" archives/install.sh
grep 'probo-agent_.*\.tar\.gz' archives/checksums.txt > archives/probo-agent-checksums.txt
awk '
/# __PROBO_AGENT_CHECKSUMS_BEGIN__/ {
print
while ((getline line < "archives/probo-agent-checksums.txt") > 0) print line
skip = 1
next
}
/# __PROBO_AGENT_CHECKSUMS_END__/ {
skip = 0
print
next
}
!skip { print }
END {
if (skip) {
print "install.sh injection failed: missing # __PROBO_AGENT_CHECKSUMS_END__ marker" > "/dev/stderr"
exit 1
}
}
' archives/install.sh > archives/install.sh.tmp
mv archives/install.sh.tmp archives/install.sh
- name: "Generate SBOM"
uses: "anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610" # v0.24.0
with:
path: ./cmd/probo-agent
format: cyclonedx-json
output-file: sbom.json
- name: "Run vulnerability scan"
uses: "anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2" # v7.4.0
with:
sbom: "sbom.json"
fail-build: true
severity-cutoff: critical
- name: "Attest SBOM for archives"
uses: "actions/attest-sbom@c604332985a26aa8cf1bdc465b92731239ec6b9e" # v4
with:
subject-path: "archives/*.tar.gz, archives/*.zip, archives/*.pkg"
sbom-path: "sbom.json"
- name: "Attest build provenance for archives"
uses: "actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373" # v4
with:
subject-path: "archives/*.tar.gz, archives/*.zip, archives/*.pkg"
- name: "Extract release notes"
run: |
VERSION="${GITHUB_REF_NAME##*/v}"
if [ -f cmd/probo-agent/CHANGELOG.md ]; then
awk -v ver="$VERSION" '
/^## \[/ { if (found) exit; if ($0 ~ "\\[" ver "\\]") found=1 }
found
' cmd/probo-agent/CHANGELOG.md > release-notes.md
else
echo "probo-agent ${VERSION}" > release-notes.md
fi
- name: "Create GitHub release"
env:
GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
run: |
PRERELEASE_FLAG=""
if echo "${GITHUB_REF_NAME}" | grep -qE '(alpha|beta|rc)'; then
PRERELEASE_FLAG="--prerelease"
fi
gh release delete "${GITHUB_REF_NAME}" --yes 2>/dev/null || true
gh release create "${GITHUB_REF_NAME}" \
--title "${GITHUB_REF_NAME}" \
--notes-file release-notes.md \
$PRERELEASE_FLAG \
archives/* sbom.json
- uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7
with:
name: "sbom"
path: "sbom.json"
retention-days: 30