Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
108 changes: 79 additions & 29 deletions .github/workflows/release-binaries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ jobs:
asset_name: codedb-linux-x86_64
zig_archive: zig-x86_64-linux-0.15.2.tar.xz
zig_dir: zig-x86_64-linux-0.15.2
- runner: ubuntu-24.04
zig_target: aarch64-linux
asset_name: codedb-linux-arm64
zig_archive: zig-x86_64-linux-0.15.2.tar.xz
zig_dir: zig-x86_64-linux-0.15.2
env:
RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.event.release.tag_name }}
APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
CODEDB_CODESIGN_IDENTITY: ${{ secrets.APPLE_CODESIGN_IDENTITY }}
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -58,41 +60,89 @@ jobs:
tar -xf zig.tar.xz
echo "$PWD/${{ matrix.zig_dir }}" >> "$GITHUB_PATH"

- name: Import Apple signing certificate
if: runner.os == 'macOS' && env.APPLE_CERTIFICATE_P12 != ''
- name: Fetch notarization helper from main
if: runner.os == 'macOS'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
CERT_PATH="$RUNNER_TEMP/codedb-signing.p12"
KEYCHAIN_PATH="$RUNNER_TEMP/codedb-signing.keychain-db"
export CERT_PATH
python3 - <<'PY'
import base64
import os
import pathlib
pathlib.Path(os.environ["CERT_PATH"]).write_bytes(
base64.b64decode(os.environ["APPLE_CERTIFICATE_P12"])
)
PY
security create-keychain -p "" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "" "$KEYCHAIN_PATH"
security import "$CERT_PATH" -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
security list-keychains -d user -s "$KEYCHAIN_PATH"
security default-keychain -s "$KEYCHAIN_PATH"
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "" "$KEYCHAIN_PATH"

- name: Build ${{ matrix.asset_name }}
mkdir -p scripts
gh api repos/${{ github.repository }}/contents/scripts/notarize-macos.sh \
-H "Accept: application/vnd.github.raw" > scripts/notarize-macos.sh
Comment on lines +71 to +72
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Pin notarization helper download to immutable ref

This step pulls scripts/notarize-macos.sh from a mutable branch tip and that script is later executed in the notarization step with APPLE_API_* secrets, so historical tag rebuilds can run different code than what was reviewed for the tag. If default-branch content changes (accidentally or maliciously), the workflow can leak notarization credentials or alter signing behavior without any change to the release tag being rebuilt. Use an immutable ref (for example, a specific commit SHA tied to the workflow revision) before executing the helper with secrets.

Useful? React with 👍 / 👎.

chmod +x scripts/notarize-macos.sh

- name: Require macOS signing and notarization secrets
if: runner.os == 'macOS'
env:
APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER_ID: ${{ secrets.APPLE_API_ISSUER_ID }}
APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }}
shell: bash
run: |
set -euo pipefail
codesign_arg=()
if [[ "${{ runner.os }}" == "macOS" ]] && grep -q 'codesign-identity' build.zig; then
codesign_arg=(-Dcodesign-identity="${CODEDB_CODESIGN_IDENTITY:-"-"}")
missing=()
[[ -n "${APPLE_CERTIFICATE_P12}" ]] || missing+=("APPLE_CERTIFICATE_P12")
[[ -n "${APPLE_CERTIFICATE_PASSWORD}" ]] || missing+=("APPLE_CERTIFICATE_PASSWORD")
[[ -n "${APPLE_API_KEY_ID}" ]] || missing+=("APPLE_API_KEY_ID")
[[ -n "${APPLE_API_ISSUER_ID}" ]] || missing+=("APPLE_API_ISSUER_ID")
[[ -n "${APPLE_API_KEY_BASE64}" ]] || missing+=("APPLE_API_KEY_BASE64")
if (( ${#missing[@]} > 0 )); then
printf 'Missing required macOS release secrets: %s\n' "${missing[*]}" >&2
exit 1
fi
zig build -Doptimize=ReleaseFast -Dtarget=${{ matrix.zig_target }} "${codesign_arg[@]}"

- name: Import Apple signing certificate
if: runner.os == 'macOS'
uses: apple-actions/import-codesign-certs@v5
with:
p12-file-base64: ${{ secrets.APPLE_CERTIFICATE_P12 }}
p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}

- name: Build ${{ matrix.asset_name }} (macOS)
if: runner.os == 'macOS'
env:
CODEDB_CODESIGN_IDENTITY: "${{ secrets.APPLE_CODESIGN_IDENTITY != '' && secrets.APPLE_CODESIGN_IDENTITY || 'Developer ID Application: Rachit Pradhan (WWP9DLJ27P)' }}"
shell: bash
run: |
set -euo pipefail
codesign_args=()
if grep -q 'codesign-identity' build.zig; then
codesign_args=(-Dcodesign-identity="${CODEDB_CODESIGN_IDENTITY}")
fi
zig build -Doptimize=ReleaseFast -Dtarget=${{ matrix.zig_target }} "${codesign_args[@]}"
cp zig-out/bin/codedb "${{ matrix.asset_name }}"

- name: Re-sign ${{ matrix.asset_name }} for notarization
if: runner.os == 'macOS'
env:
CODEDB_CODESIGN_IDENTITY: "${{ secrets.APPLE_CODESIGN_IDENTITY != '' && secrets.APPLE_CODESIGN_IDENTITY || 'Developer ID Application: Rachit Pradhan (WWP9DLJ27P)' }}"
shell: bash
run: |
set -euo pipefail
codesign -f -s "${CODEDB_CODESIGN_IDENTITY}" --options runtime --timestamp "${{ matrix.asset_name }}"

- name: Build ${{ matrix.asset_name }} (Linux)
if: runner.os != 'macOS'
shell: bash
run: |
set -euo pipefail
zig build -Doptimize=ReleaseFast -Dtarget=${{ matrix.zig_target }}
cp zig-out/bin/codedb "${{ matrix.asset_name }}"

- name: Notarize ${{ matrix.asset_name }}
if: runner.os == 'macOS'
env:
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER_ID: ${{ secrets.APPLE_API_ISSUER_ID }}
APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }}
shell: bash
run: |
set -euo pipefail
bash scripts/notarize-macos.sh "${{ matrix.asset_name }}"

- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
Expand Down
6 changes: 5 additions & 1 deletion build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ pub fn build(b: *std.Build) void {

// ── macOS codesign (ad-hoc by default; configurable for release builds) ──
if (target.result.os.tag == .macos and builtin.os.tag == .macos) {
const codesign = b.addSystemCommand(&.{ "codesign", "-f", "-s", codesign_identity });
const codesign_args = if (std.mem.eql(u8, codesign_identity, "-"))
&.{ "codesign", "-f", "-s", codesign_identity }
else
&.{ "codesign", "-f", "-s", codesign_identity, "--options", "runtime", "--timestamp" };
const codesign = b.addSystemCommand(codesign_args);
codesign.addArtifactArg(exe);
b.getInstallStep().dependOn(&codesign.step);
}
Expand Down
44 changes: 44 additions & 0 deletions scripts/notarize-macos.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -euo pipefail

if [[ $# -ne 1 ]]; then
echo "usage: $0 <binary-path>" >&2
exit 1
fi

binary_path="$1"

: "${APPLE_API_KEY_ID:?APPLE_API_KEY_ID is required}"
: "${APPLE_API_ISSUER_ID:?APPLE_API_ISSUER_ID is required}"
: "${APPLE_API_KEY_BASE64:?APPLE_API_KEY_BASE64 is required}"

tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/codedb-notary.XXXXXX")"
api_key_path="$tmp_dir/codedb-notary-key.p8"
zip_path="$tmp_dir/$(basename "$binary_path").zip"
export API_KEY_PATH="$api_key_path"

cleanup() {
rm -rf "$tmp_dir"
}
trap cleanup EXIT

python3 - <<'PY'
import base64
import os
import pathlib

pathlib.Path(os.environ["API_KEY_PATH"]).write_bytes(
base64.b64decode(os.environ["APPLE_API_KEY_BASE64"])
)
PY

chmod 600 "$api_key_path"
codesign --verify --verbose=2 "$binary_path"
ditto -c -k --keepParent "$binary_path" "$zip_path"
xcrun notarytool submit "$zip_path" \
--key "$api_key_path" \
--key-id "$APPLE_API_KEY_ID" \
--issuer "$APPLE_API_ISSUER_ID" \
--wait
xcrun stapler staple "$binary_path" || true
spctl --assess --type execute --verbose=4 "$binary_path"
Loading