cloudflare/cloudflared

Public

mirrored from https://github.com/cloudflare/cloudflaredAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2026.2.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

.ci/scripts/mac/build.sh

228lines · modecode

1#!/bin/bash
2
3set -exo pipefail
4
5if [[ "$(uname)" != "Darwin" ]] ; then
6 echo "This should be run on macOS"
7 exit 1
8fi
9
10if [[ "amd64" != "${TARGET_ARCH}" && "arm64" != "${TARGET_ARCH}" ]]
11then
12 echo "TARGET_ARCH must be amd64 or arm64"
13 exit 1
14fi
15
16go version
17export GO111MODULE=on
18
19# build 'cloudflared-darwin-amd64.tgz'
20mkdir -p artifacts
21TARGET_DIRECTORY=".build"
22BINARY_NAME="cloudflared"
23VERSION=$(git describe --tags --always --dirty="-dev")
24PRODUCT="cloudflared"
25APPLE_CA_CERT="apple_dev_ca.cert"
26CODE_SIGN_PRIV="code_sign.p12"
27CODE_SIGN_CERT="code_sign.cer"
28INSTALLER_PRIV="installer.p12"
29INSTALLER_CERT="installer.cer"
30BUNDLE_ID="com.cloudflare.cloudflared"
31SEC_DUP_MSG="security: SecKeychainItemImport: The specified item already exists in the keychain."
32export PATH="$PATH:/usr/local/bin"
33FILENAME="$(pwd)/artifacts/cloudflared-darwin-$TARGET_ARCH.tgz"
34PKGNAME="$(pwd)/artifacts/cloudflared-$TARGET_ARCH.pkg"
35mkdir -p ../src/github.com/cloudflare/
36cp -r . ../src/github.com/cloudflare/cloudflared
37cd ../src/github.com/cloudflare/cloudflared
38
39# Imports certificates to the Apple KeyChain
40import_certificate() {
41 local CERTIFICATE_NAME=$1
42 local CERTIFICATE_ENV_VAR=$2
43 local CERTIFICATE_FILE_NAME=$3
44
45 echo "Importing $CERTIFICATE_NAME"
46
47 if [[ ! -z "$CERTIFICATE_ENV_VAR" ]]; then
48 # write certificate to disk and then import it keychain
49 echo -n -e ${CERTIFICATE_ENV_VAR} | base64 -D > ${CERTIFICATE_FILE_NAME}
50 # we set || true here and for every `security import invoke` because the "duplicate SecKeychainItemImport" error
51 # will cause set -e to exit 1. It is okay we do this because we deliberately handle this error in the lines below.
52 local out=$(security import ${CERTIFICATE_FILE_NAME} -T /usr/bin/pkgbuild -A 2>&1) || true
53 local exitcode=$?
54 # delete the certificate from disk
55 rm -rf ${CERTIFICATE_FILE_NAME}
56 if [ -n "$out" ]; then
57 if [ $exitcode -eq 0 ]; then
58 echo "$out"
59 else
60 if [ "$out" != "${SEC_DUP_MSG}" ]; then
61 echo "$out" >&2
62 exit $exitcode
63 else
64 echo "already imported code signing certificate"
65 fi
66 fi
67 fi
68 fi
69}
70
71create_cloudflared_build_keychain() {
72 # Reusing the private key password as the keychain key
73 local PRIVATE_KEY_PASS=$1
74
75 # Create keychain only if it doesn't already exist
76 if [ ! -f "$HOME/Library/Keychains/cloudflared_build_keychain.keychain-db" ]; then
77 security create-keychain -p "$PRIVATE_KEY_PASS" cloudflared_build_keychain
78 else
79 echo "Keychain already exists: cloudflared_build_keychain"
80 fi
81
82 # Append temp keychain to the user domain
83 security list-keychains -d user -s cloudflared_build_keychain $(security list-keychains -d user | sed s/\"//g)
84
85 # Remove relock timeout
86 security set-keychain-settings cloudflared_build_keychain
87
88 # Unlock keychain so it doesn't require password
89 security unlock-keychain -p "$PRIVATE_KEY_PASS" cloudflared_build_keychain
90
91}
92
93# Imports private keys to the Apple KeyChain
94import_private_keys() {
95 local PRIVATE_KEY_NAME=$1
96 local PRIVATE_KEY_ENV_VAR=$2
97 local PRIVATE_KEY_FILE_NAME=$3
98 local PRIVATE_KEY_PASS=$4
99
100 echo "Importing $PRIVATE_KEY_NAME"
101
102 if [[ ! -z "$PRIVATE_KEY_ENV_VAR" ]]; then
103 if [[ ! -z "$PRIVATE_KEY_PASS" ]]; then
104 # write private key to disk and then import it keychain
105 echo -n -e ${PRIVATE_KEY_ENV_VAR} | base64 -D > ${PRIVATE_KEY_FILE_NAME}
106 # we set || true here and for every `security import invoke` because the "duplicate SecKeychainItemImport" error
107 # will cause set -e to exit 1. It is okay we do this because we deliberately handle this error in the lines below.
108 local out=$(security import ${PRIVATE_KEY_FILE_NAME} -k cloudflared_build_keychain -P "$PRIVATE_KEY_PASS" -T /usr/bin/pkgbuild -A -P "${PRIVATE_KEY_PASS}" 2>&1) || true
109 local exitcode=$?
110 rm -rf ${PRIVATE_KEY_FILE_NAME}
111 if [ -n "$out" ]; then
112 if [ $exitcode -eq 0 ]; then
113 echo "$out"
114 else
115 if [ "$out" != "${SEC_DUP_MSG}" ]; then
116 echo "$out" >&2
117 exit $exitcode
118 fi
119 fi
120 fi
121 fi
122 fi
123}
124
125# Create temp keychain only for this build
126create_cloudflared_build_keychain "${CFD_CODE_SIGN_PASS}"
127
128# Add Apple Root Developer certificate to the key chain
129import_certificate "Apple Developer CA" "${APPLE_DEV_CA_CERT}" "${APPLE_CA_CERT}"
130
131# Add code signing private key to the key chain
132import_private_keys "Developer ID Application" "${CFD_CODE_SIGN_KEY}" "${CODE_SIGN_PRIV}" "${CFD_CODE_SIGN_PASS}"
133
134# Add code signing certificate to the key chain
135import_certificate "Developer ID Application" "${CFD_CODE_SIGN_CERT}" "${CODE_SIGN_CERT}"
136
137# Add package signing private key to the key chain
138import_private_keys "Developer ID Installer" "${CFD_INSTALLER_KEY}" "${INSTALLER_PRIV}" "${CFD_INSTALLER_PASS}"
139
140# Add package signing certificate to the key chain
141import_certificate "Developer ID Installer" "${CFD_INSTALLER_CERT}" "${INSTALLER_CERT}"
142
143# get the code signing certificate name
144if [[ ! -z "$CFD_CODE_SIGN_NAME" ]]; then
145 CODE_SIGN_NAME="${CFD_CODE_SIGN_NAME}"
146else
147 if [[ -n "$(security find-certificate -c "Developer ID Application" cloudflared_build_keychain | cut -d'"' -f 4 -s | grep "Developer ID Application:" | head -1)" ]]; then
148 CODE_SIGN_NAME=$(security find-certificate -c "Developer ID Application" cloudflared_build_keychain | cut -d'"' -f 4 -s | grep "Developer ID Application:" | head -1)
149 else
150 CODE_SIGN_NAME=""
151 fi
152fi
153
154# get the package signing certificate name
155if [[ ! -z "$CFD_INSTALLER_NAME" ]]; then
156 PKG_SIGN_NAME="${CFD_INSTALLER_NAME}"
157else
158 if [[ -n "$(security find-certificate -c "Developer ID Installer" cloudflared_build_keychain | cut -d'"' -f 4 -s | grep "Developer ID Installer:" | head -1)" ]]; then
159 PKG_SIGN_NAME=$(security find-certificate -c "Developer ID Installer" cloudflared_build_keychain | cut -d'"' -f 4 -s | grep "Developer ID Installer:" | head -1)
160 else
161 PKG_SIGN_NAME=""
162 fi
163fi
164
165# cleanup the build directory because the previous execution might have failed without cleaning up.
166rm -rf "${TARGET_DIRECTORY}"
167export TARGET_OS="darwin"
168GOCACHE="$PWD/../../../../" GOPATH="$PWD/../../../../" CGO_ENABLED=1 make cloudflared
169
170
171# This allows apple tools to use the certificates in the keychain without requiring password input.
172# This command always needs to run after the certificates have been loaded into the keychain
173if [[ ! -z "$CFD_CODE_SIGN_PASS" ]]; then
174 security set-key-partition-list -S apple-tool:,apple: -s -k "${CFD_CODE_SIGN_PASS}" cloudflared_build_keychain
175fi
176
177# sign the cloudflared binary
178if [[ ! -z "$CODE_SIGN_NAME" ]]; then
179 codesign --keychain $HOME/Library/Keychains/cloudflared_build_keychain.keychain-db -s "${CODE_SIGN_NAME}" -fv --options runtime --timestamp ${BINARY_NAME}
180
181 # notarize the binary
182 # TODO: TUN-5789
183fi
184
185ARCH_TARGET_DIRECTORY="${TARGET_DIRECTORY}/${TARGET_ARCH}-build"
186# creating build directory
187rm -rf $ARCH_TARGET_DIRECTORY
188mkdir -p "${ARCH_TARGET_DIRECTORY}"
189mkdir -p "${ARCH_TARGET_DIRECTORY}/contents"
190cp -r ".mac_resources/scripts" "${ARCH_TARGET_DIRECTORY}/scripts"
191
192# copy cloudflared into the build directory
193cp ${BINARY_NAME} "${ARCH_TARGET_DIRECTORY}/contents/${PRODUCT}"
194
195# compress cloudflared into a tar and gzipped file
196tar czf "$FILENAME" "${BINARY_NAME}"
197
198# build the installer package
199if [[ ! -z "$PKG_SIGN_NAME" ]]; then
200
201 pkgbuild --identifier com.cloudflare.${PRODUCT} \
202 --version ${VERSION} \
203 --scripts ${ARCH_TARGET_DIRECTORY}/scripts \
204 --root ${ARCH_TARGET_DIRECTORY}/contents \
205 --install-location /usr/local/bin \
206 --keychain cloudflared_build_keychain \
207 --sign "${PKG_SIGN_NAME}" \
208 ${PKGNAME}
209
210 # notarize the package
211 # TODO: TUN-5789
212else
213 pkgbuild --identifier com.cloudflare.${PRODUCT} \
214 --version ${VERSION} \
215 --scripts ${ARCH_TARGET_DIRECTORY}/scripts \
216 --root ${ARCH_TARGET_DIRECTORY}/contents \
217 --install-location /usr/local/bin \
218 ${PKGNAME}
219fi
220
221# cleanup build directory because this script is not ran within containers,
222# which might lead to future issues in subsequent runs.
223rm -rf "${TARGET_DIRECTORY}"
224
225# cleanup the keychain
226security default-keychain -d user -s login.keychain-db
227security list-keychains -d user -s login.keychain-db
228security delete-keychain cloudflared_build_keychain
229