From 6a58fc82c553bc69966133594393b1f57f1b3717 Mon Sep 17 00:00:00 2001 From: Rian Stockbower Date: Thu, 4 Jun 2026 06:06:07 -0400 Subject: [PATCH] =?UTF-8?q?docs:=20update=20=C2=A72A=20codesign=20hook=20s?= =?UTF-8?q?nippet=20to=20the=20fail-loud=20form?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The canonical §2A snippet showed the original simple hook, but all six family CLIs ship the hardened fail-loud form. Match the doc to reality: CODESIGN_DARWIN_SCRIPT unset → skip (local/opt-out); set but missing or non-executable → error and fail the build instead of silently shipping an unsigned binary. Also clarify the surrounding prose to spell out the three cases. --- docs/distribution.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/distribution.md b/docs/distribution.md index 82570f6..7140cd4 100644 --- a/docs/distribution.md +++ b/docs/distribution.md @@ -116,12 +116,14 @@ darwin build adds exactly one byte-identical hook: ```yaml hooks: post: - - cmd: bash -c 'f="${CODESIGN_DARWIN_SCRIPT:-}"; [ -n "$f" ] && [ -x "$f" ] && exec "$f" "$0" "$1"; echo "skip codesign (no CODESIGN_DARWIN_SCRIPT)"' "{{ .Path }}" "{{ .Os }}" + - cmd: bash -c 'f="${CODESIGN_DARWIN_SCRIPT:-}"; if [ -z "$f" ]; then echo "skip codesign (CODESIGN_DARWIN_SCRIPT unset, local build)"; exit 0; fi; [ -x "$f" ] || { echo "CODESIGN_DARWIN_SCRIPT not executable ($f)" >&2; exit 1; }; exec "$f" "$0" "$1"' "{{ .Path }}" "{{ .Os }}" ``` The hook uses the **absolute** `$CODESIGN_DARWIN_SCRIPT` (a build hook's CWD is the -build's `dir:`, e.g. `tools/cfl`, so a repo-relative path would miss) and no-ops in -local builds where the env is unset. Signing setup and `check-signature` enforcement +build's `dir:`, e.g. `tools/cfl`, so a repo-relative path would miss) and is +**fail-loud**: env **unset** → skip (the local-build / opt-out path); env **set but the +script is missing or non-executable** → error and fail the build, rather than silently +shipping an unsigned binary in a release that intended to sign. Signing setup and `check-signature` enforcement are both **self-gated on whether the cert secrets were passed** (`secrets.*` is not available in `if:`, so the gate lives inside the composites, keyed on their inputs): both off for a caller that hasn't opted in, both on the moment it passes the four