113 lines
3.7 KiB
Bash
Executable file
113 lines
3.7 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Validate OpenPencil's macOS local-network privacy metadata.
|
|
#
|
|
# With plist arguments, this checks the exact files. With no arguments, it
|
|
# checks the cargo-bundle extension metadata and all repository packaging /
|
|
# release integration points.
|
|
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
# shellcheck source=macos-local-network-plist.sh
|
|
source "$ROOT/tools/macos-local-network-plist.sh"
|
|
|
|
fail() {
|
|
printf 'macos-bundle-plist: error: %s\n' "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
require_regex() {
|
|
local file=$1
|
|
local pattern=$2
|
|
local reason=$3
|
|
grep -Eq -- "$pattern" "$file" ||
|
|
fail "$file: $reason"
|
|
}
|
|
|
|
check_plists() {
|
|
OPENPENCIL_EXPECTED_LOCAL_NETWORK_DESCRIPTION="$OPENPENCIL_LOCAL_NETWORK_USAGE_DESCRIPTION" \
|
|
OPENPENCIL_EXPECTED_BONJOUR_SERVICE="$OPENPENCIL_BONJOUR_SERVICE" \
|
|
python3 - "$@" <<'PY'
|
|
import os
|
|
import plistlib
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
expected_description = os.environ["OPENPENCIL_EXPECTED_LOCAL_NETWORK_DESCRIPTION"]
|
|
expected_service = os.environ["OPENPENCIL_EXPECTED_BONJOUR_SERVICE"]
|
|
failed = False
|
|
|
|
for raw_path in sys.argv[1:]:
|
|
path = Path(raw_path)
|
|
try:
|
|
with path.open("rb") as handle:
|
|
plist = plistlib.load(handle)
|
|
except (OSError, plistlib.InvalidFileException) as error:
|
|
print(f"macos-bundle-plist: error: {path}: invalid plist: {error}", file=sys.stderr)
|
|
failed = True
|
|
continue
|
|
|
|
description = plist.get("NSLocalNetworkUsageDescription")
|
|
if description != expected_description:
|
|
print(
|
|
"macos-bundle-plist: error: "
|
|
f"{path}: NSLocalNetworkUsageDescription must equal "
|
|
f"{expected_description!r}, got {description!r}",
|
|
file=sys.stderr,
|
|
)
|
|
failed = True
|
|
|
|
services = plist.get("NSBonjourServices")
|
|
if services != [expected_service]:
|
|
print(
|
|
"macos-bundle-plist: error: "
|
|
f"{path}: NSBonjourServices must equal [{expected_service!r}], "
|
|
f"got {services!r}",
|
|
file=sys.stderr,
|
|
)
|
|
failed = True
|
|
|
|
if failed:
|
|
raise SystemExit(1)
|
|
PY
|
|
}
|
|
|
|
if (($# > 0)); then
|
|
check_plists "$@"
|
|
printf 'macos-bundle-plist: PASS (%s plist file(s))\n' "$#"
|
|
exit 0
|
|
fi
|
|
|
|
check_plists "$ROOT/crates/op-host-desktop/Info.plist"
|
|
|
|
for bundle_script in scripts/bundle-macos.sh tools/bundle-macos.sh; do
|
|
require_regex \
|
|
"$ROOT/$bundle_script" \
|
|
'^[[:space:]]*(source|[.])[[:space:]]+.*macos-local-network-plist[.]sh' \
|
|
'must source the canonical local-network metadata'
|
|
require_regex \
|
|
"$ROOT/$bundle_script" \
|
|
'^[[:space:]]*openpencil_apply_macos_local_network_plist[[:space:]]+"\$PLIST"[[:space:]]*$' \
|
|
'must patch the final bundle Info.plist through the canonical helper'
|
|
require_regex \
|
|
"$ROOT/$bundle_script" \
|
|
'^[[:space:]]*bash[[:space:]]+".*check-macos-bundle-plist[.]sh"[[:space:]]+"\$PLIST"[[:space:]]*$' \
|
|
'must validate the final bundle Info.plist'
|
|
done
|
|
|
|
release_workflow="$ROOT/.github/workflows/rust-release.yml"
|
|
require_regex \
|
|
"$release_workflow" \
|
|
'^[[:space:]]*bash[[:space:]]+scripts/bundle-macos[.]sh[[:space:]]*$' \
|
|
'release workflow must use the production macOS bundle script'
|
|
require_regex \
|
|
"$release_workflow" \
|
|
'^[[:space:]]*bash[[:space:]]+tools/check-macos-bundle-plist[.]sh[[:space:]]+\\[[:space:]]*$' \
|
|
'release workflow must validate the assembled app Info.plist before notarization'
|
|
require_regex \
|
|
"$release_workflow" \
|
|
'^[[:space:]]*"target/\$\{\{ matrix[.]target \}\}/release/bundle/osx/OpenPencil[.]app/Contents/Info[.]plist"[[:space:]]*$' \
|
|
'release workflow must validate the exact app path it notarizes'
|
|
|
|
printf 'macos-bundle-plist: PASS (source metadata and release integration)\n'
|