diff --git a/Packaging/DeveloperID/build_release.sh b/Packaging/DeveloperID/build_release.sh index 15cbe0c..919df65 100755 --- a/Packaging/DeveloperID/build_release.sh +++ b/Packaging/DeveloperID/build_release.sh @@ -4,6 +4,7 @@ set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" source "$ROOT_DIR/script/release_path_guard.sh" source "$ROOT_DIR/script/disk_image_tools.sh" +source "$ROOT_DIR/Packaging/DeveloperID/codesign_details.sh" PACKAGE_DIR="$ROOT_DIR/SwiftExplorerApp" PACKAGING_DIR="$ROOT_DIR/Packaging/DeveloperID" OUTPUT_NAME="${DEVELOPER_ID_OUTPUT_NAME:-developer-id}" @@ -215,7 +216,7 @@ validate_app() { if [[ "$SKIP_SIGNING" -eq 0 ]]; then grep -F 'Authority=Developer ID Application:' "$signature_output" >/dev/null grep -F "TeamIdentifier=$EXPECTED_TEAM_ID" "$signature_output" >/dev/null - grep -E '^flags=.*runtime' "$signature_output" >/dev/null + codesign_details_has_hardened_runtime "$signature_output" grep -F 'Timestamp=' "$signature_output" >/dev/null fi } diff --git a/Packaging/DeveloperID/codesign_details.sh b/Packaging/DeveloperID/codesign_details.sh new file mode 100644 index 0000000..ca74855 --- /dev/null +++ b/Packaging/DeveloperID/codesign_details.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +codesign_details_has_hardened_runtime() { + if [[ $# -ne 1 || ! -f "$1" ]]; then + return 2 + fi + + grep -Eq '(^|[[:space:]])flags=[^[:space:]]*[(,]runtime[),]' "$1" +} diff --git a/Packaging/DeveloperID/tests/codesign_details_contract_test.sh b/Packaging/DeveloperID/tests/codesign_details_contract_test.sh new file mode 100755 index 0000000..1f640fa --- /dev/null +++ b/Packaging/DeveloperID/tests/codesign_details_contract_test.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +CHECKS="$ROOT_DIR/Packaging/DeveloperID/codesign_details.sh" +TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/codebase-combiner-codesign-details.XXXXXX")" +trap 'rm -rf "$TMP_DIR"' EXIT + +if [[ ! -f "$CHECKS" ]]; then + echo "Code-signing detail checks are missing: $CHECKS" >&2 + exit 1 +fi +source "$CHECKS" + +cat > "$TMP_DIR/current.txt" <<'DETAILS' +Executable=/Applications/Codebase Combiner.app/Contents/MacOS/CodebaseExplorerApp +CodeDirectory v=20500 size=4521 flags=0x10000(runtime) hashes=130+7 location=embedded +Runtime Version=26.5.0 +DETAILS + +cat > "$TMP_DIR/legacy.txt" <<'DETAILS' +Executable=/Applications/Codebase Combiner.app/Contents/MacOS/CodebaseExplorerApp +flags=0x10000(runtime) +DETAILS + +cat > "$TMP_DIR/no-runtime-flag.txt" <<'DETAILS' +CodeDirectory v=20500 size=4521 flags=0x0(none) hashes=130+7 location=embedded +Runtime Version=26.5.0 +DETAILS + +cat > "$TMP_DIR/misleading-runtime.txt" <<'DETAILS' +CodeDirectory v=20500 size=4521 flags=0x0(none) hashes=130+7 location=embedded +Path=/tmp/runtime/Codebase Combiner.app +DETAILS + +codesign_details_has_hardened_runtime "$TMP_DIR/current.txt" +codesign_details_has_hardened_runtime "$TMP_DIR/legacy.txt" + +if codesign_details_has_hardened_runtime "$TMP_DIR/no-runtime-flag.txt"; then + echo "Runtime version metadata was mistaken for the hardened-runtime signing flag." >&2 + exit 1 +fi + +if codesign_details_has_hardened_runtime "$TMP_DIR/misleading-runtime.txt"; then + echo "An unrelated runtime path was mistaken for the hardened-runtime signing flag." >&2 + exit 1 +fi + +echo "Code-signing details contract passed" diff --git a/Packaging/DeveloperID/tests/run_tests.sh b/Packaging/DeveloperID/tests/run_tests.sh index b268bc0..d69c50a 100755 --- a/Packaging/DeveloperID/tests/run_tests.sh +++ b/Packaging/DeveloperID/tests/run_tests.sh @@ -3,6 +3,7 @@ set -euo pipefail TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +bash "$TEST_DIR/codesign_details_contract_test.sh" bash "$TEST_DIR/build_release_contract_test.sh" bash "$TEST_DIR/notarize_release_contract_test.sh"