Tags: #go #macos #network #security
# 0. Have a binary to codesign.
# NOTE: I use `if os.Getenv("SKIP_FTP") != "" { t.Skip("...") }` to allow skipping the test when running the full test suite.
go test -c -o ./path/to/package/test_binary ./path/to/package
# 1. Create self-signed private key and certificate
# IMPORTANT: The `-addext` flags are essential for codesigning purposes.
openssl req -new -x509 -days 365 -nodes \
-keyout ExampleTestBinaryCodeSigning.key -out ExampleTestBinaryCodeSigning.crt \
-subj "/CN=ExampleTestBinaryCodeSigning" \
-addext "keyUsage=digitalSignature,keyEncipherment" \
-addext "extendedKeyUsage=codeSigning"
# 2. Export private key and certificate as p12.
# IMPORTANT: The `-legacy` flag is essential if using OpenSSL 3.x on macOS.
# OpenSSL 3.x changed its default algorithm in pkcs12.
# Which is not compatible with embedded Security frameworks in macOS/iOS.
# So you either downgrade to OpenSSL 1.1 or use -legacy flag.
openssl pkcs12 -export \
-out ExampleTestBinaryCodeSigning.p12 \
-inkey ExampleTestBinaryCodeSigning.key \
-in ExampleTestBinaryCodeSigning.crt \
-legacy \
-passout pass:whatever
# 3. Validate the password has been set on your p12 (-nokeys vs -noout == just different output)
openssl pkcs12 -info -nokeys -in ExampleTestBinaryCodeSigning.p12 -legacy -password pass:whatever
openssl pkcs12 -info -noout -in ExampleTestBinaryCodeSigning.p12 -legacy -password pass:whatever
# 4. List your keychains so you know which one you're going to reference and where it is located.
# It can be extracted automatically using `security list | awk '/login.keychain/ { print $1 }'`
security list
# 5. Import your p12 into your keychain.
security import ExampleTestBinaryCodeSigning.p12 -k ~/Library/Keychains/login.keychain-db -P whatever -T /usr/bin/codesign
# 6. Find the certificate in your keychain.
security find-certificate -a -c "ExampleTestBinaryCodeSigning" -p
# 7. Check the details of the certificate in the keychain.
security find-certificate -c "ExampleTestBinaryCodeSigning"
# 8. Set the certificate to be trusted.
# Only possible if you still have the cert.
# Otherwise you have to manually trust it via the "Keychain Access" GUI.
security add-trusted-cert -d -r trustRoot -k ~/Library/Keychains/login.keychain-db ./ExampleTestBinaryCodeSigning.crt
# 9. Validate you have 'valid' identities.
security find-identity -v
security find-identity -p codesigning -v
# 10. Now you may codesign your binary.
codesign -f -s "ExampleTestBinaryCodeSigning" ./path/to/package/test_binary
.PHONY: codesigning
codesigning: ID=ExampleTestBinaryCodeSigningIdentity
codesigning: CERT_PSW=whatever
codesigning:
@if [ $$(uname) == "Darwin" ] && [ "$$(security find-certificate -a -c "$(ID)" -p)" == "" ]; then \
echo ""; \
echo "⚠️ no code-signing certificate found in your keychain (so we'll try to generate that for you)"; \
echo ""; \
openssl req -new -x509 -days 365 -nodes \
-keyout $(ID).key -out $(ID).crt \
-subj "/CN=$(ID)" \
-addext "keyUsage=digitalSignature,keyEncipherment" \
-addext "extendedKeyUsage=codeSigning"; \
openssl pkcs12 -export \
-out $(ID).p12 \
-inkey $(ID).key \
-in $(ID).crt \
-legacy \
-passout pass:$(CERT_PSW); \
trap "rm -f $(ID)*" EXIT; \
kc=$$(security list | awk '/login.keychain/ { gsub(/^ *| *$$/, ""); print $$1 }' | sed 's/"//g'); \
security import $(ID).p12 \
-k "$$kc" \
-P $(CERT_PSW) \
-T /usr/bin/codesign; \
security add-trusted-cert -d -r trustRoot -k $$kc $(ID).crt; \
if security find-identity -p codesigning -v | grep '0 valid identities found'; then \
echo "🚨 failed to find a valid code-signing identity"; \
exit 1; \
fi \
fi
.PHONY: test
test: codesigning ## Run project's test suite with race detection
@if [ $$(uname) == "Darwin" ]; then \
go test -c -o ./path/to/package/test_binary ./path/to/package; \
codesign -f -s "ExampleTestBinaryCodeSigningIdentity" ./path/to/package/test_binary; \
trap "rm -f ./path/to/package/test_binary" EXIT; \
cd ./path/to/package/ && { ./test_binary; cd -; } || cd -; \
# SKIP_FTP forces the go toolchain to skip the problematic test that uses the network; \
SKIP_FTP=true go test -race -v -count=1 $(GO_BUILDARGS) $(GO_TESTARGS) $(APP_TESTARGS); \
else \
go test -race -v -count=1 $(GO_BUILDARGS) $(GO_TESTARGS) $(APP_TESTARGS); \
fi