#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" UPDATER="${ROOT_DIR}/scripts/transport-packaging/update.sh" require_cmd() { local cmd="$1" if ! command -v "$cmd" >/dev/null 2>&1; then echo "[transport_packaging_policy_rollout] missing command: ${cmd}" >&2 exit 1 fi } require_cmd bash require_cmd openssl require_cmd sha256sum require_cmd jq tmp_dir="$(mktemp -d)" trap 'rm -rf "$tmp_dir"' EXIT assets_dir="${tmp_dir}/assets" bin_root="${tmp_dir}/bin-root" keys_dir="${tmp_dir}/keys" mkdir -p "$assets_dir" "$bin_root" "$keys_dir" asset_v1="${assets_dir}/sing-box-v1" asset_v2="${assets_dir}/sing-box-v2" sig_v1="${assets_dir}/sing-box-v1.sig" sig_v2="${assets_dir}/sing-box-v2.sig" sig_bad="${assets_dir}/sing-box-v2.bad.sig" cat >"$asset_v1" <<'EOF' #!/usr/bin/env bash echo "signed sing-box v1" EOF chmod +x "$asset_v1" cat >"$asset_v2" <<'EOF' #!/usr/bin/env bash echo "signed sing-box v2" EOF chmod +x "$asset_v2" sha_v1="$(sha256sum "$asset_v1" | awk '{print $1}')" sha_v2="$(sha256sum "$asset_v2" | awk '{print $1}')" openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out "${keys_dir}/release-private.pem" >/dev/null 2>&1 openssl rsa -pubout -in "${keys_dir}/release-private.pem" -out "${keys_dir}/release-public.pem" >/dev/null 2>&1 openssl dgst -sha256 -sign "${keys_dir}/release-private.pem" -out "$sig_v1" "$asset_v1" openssl dgst -sha256 -sign "${keys_dir}/release-private.pem" -out "$sig_v2" "$asset_v2" cp "$sig_v1" "$sig_bad" sig_sha_v1="$(sha256sum "$sig_v1" | awk '{print $1}')" sig_sha_v2="$(sha256sum "$sig_v2" | awk '{print $1}')" sig_sha_bad="$(sha256sum "$sig_bad" | awk '{print $1}')" policy="${tmp_dir}/source-policy.json" cat >"$policy" <<'EOF' { "schema_version": 1, "require_https": false, "allow_file_scheme": true, "signature": { "default_mode": "required", "allowed_types": ["openssl-sha256"] }, "components": { "singbox": { "allowed_url_prefixes": ["file://"], "signature_mode": "required" } } } EOF manifest="${tmp_dir}/manifest-canary.json" cat >"$manifest" < skip" "$UPDATER" --manifest "$manifest" --source-policy "$policy" --bin-root "$bin_root" --component singbox --target linux-amd64 --rollout-stage stable --cohort-id 5 if [[ -e "${bin_root}/sing-box" ]]; then echo "[transport_packaging_policy_rollout] expected no install on stage mismatch" >&2 exit 1 fi echo "[transport_packaging_policy_rollout] canary gated by cohort -> skip" "$UPDATER" --manifest "$manifest" --source-policy "$policy" --bin-root "$bin_root" --component singbox --target linux-amd64 --rollout-stage canary --cohort-id 55 if [[ -e "${bin_root}/sing-box" ]]; then echo "[transport_packaging_policy_rollout] expected no install when cohort is out of rollout percent" >&2 exit 1 fi echo "[transport_packaging_policy_rollout] canary in cohort -> install" "$UPDATER" --manifest "$manifest" --source-policy "$policy" --bin-root "$bin_root" --component singbox --target linux-amd64 --rollout-stage canary --cohort-id 5 out_v1="$("${bin_root}/sing-box")" if [[ "$out_v1" != "signed sing-box v1" ]]; then echo "[transport_packaging_policy_rollout] expected signed v1 output, got: ${out_v1}" >&2 exit 1 fi echo "[transport_packaging_policy_rollout] untrusted source must fail" manifest_untrusted="${tmp_dir}/manifest-untrusted.json" jq \ '.components.singbox.targets["linux-amd64"].version = "1.1.0" | .components.singbox.targets["linux-amd64"].url = "https://example.com/sing-box" | .components.singbox.targets["linux-amd64"].sha256 = "0000000000000000000000000000000000000000000000000000000000000000" | .components.singbox.targets["linux-amd64"].rollout.stage = "stable" | .components.singbox.targets["linux-amd64"].rollout.percent = 100' \ "$manifest" >"$manifest_untrusted" if "$UPDATER" --manifest "$manifest_untrusted" --source-policy "$policy" --bin-root "$bin_root" --component singbox --target linux-amd64 --rollout-stage stable --cohort-id 5 --dry-run; then echo "[transport_packaging_policy_rollout] expected failure for untrusted source" >&2 exit 1 fi echo "[transport_packaging_policy_rollout] bad signature must fail" manifest_bad_sig="${tmp_dir}/manifest-bad-sig.json" cat >"$manifest_bad_sig" <&2 exit 1 fi echo "[transport_packaging_policy_rollout] valid signature update -> install v2" manifest_good_sig="${tmp_dir}/manifest-good-sig.json" cat >"$manifest_good_sig" <&2 exit 1 fi echo "[transport_packaging_policy_rollout] passed"