set -eu
: "${RK_REPO:?rk sets this; run this script through rk setup}"
: "${RK_TRUNK_BRANCH:?rk sets this; run this script through rk setup}"
: "${RK_BYPASS_ACTORS:?rk sets this; run this script through rk setup}"
: "${RK_TRUNK_RULESET:?rk sets this; run this script through rk setup}"
: "${RK_SAFETY_RULESET:?rk sets this; run this script through rk setup}"
: "${RK_TITLE_CHECK:?rk sets this; run this script through rk setup}"
trunk_name="$RK_TRUNK_RULESET"
safety_name="$RK_SAFETY_RULESET"
tags_name=release-tags
lines_name=release-lines
names="$(gh api "repos/$RK_REPO/rulesets" -q '.[].name' | sort)"
extra="$names"
status=0
for pair in "$trunk_name:protect-trunk" "$safety_name:protect-trunk" "$tags_name:protect-tags"; do
name="${pair%%:*}"
extra="$(printf '%s\n' "$extra" | grep -vxF "$name" || true)"
if printf '%s\n' "$names" | grep -qxF "$name"; then
echo "ok $name"
continue
fi
echo "FAIL missing ruleset: $name" >&2
echo "remediation: rk setup step ${pair#*:} --apply" >&2
status=1
done
extra="$(printf '%s\n' "$extra" | grep -vxF "$lines_name" || true)"
if printf '%s\n' "$names" | grep -qxF "$lines_name"; then
echo "ok $lines_name"
fi
if [ -n "$extra" ]; then
echo 'FAIL rulesets no step owns:' >&2
printf '%s\n' "$extra" >&2
echo 'remediation: delete each one in the repository settings' >&2
status=1
fi
check() {
id="$1"
label="$2"
expected="$3"
remedy="$4"
actual="$(gh api "repos/$RK_REPO/rulesets/$id" -q "$5")"
if [ "$actual" = "$expected" ]; then
echo "ok $label"
else
echo "FAIL $label: expected $expected, got $actual" >&2
echo "remediation: $remedy" >&2
status=1
fi
}
id="$(gh api "repos/$RK_REPO/rulesets" -q ".[] | select(.name == \"$trunk_name\") | .id" | head -n 1)"
if [ -n "$id" ]; then
rerun='rk setup step protect-trunk --apply'
check "$id" "$trunk_name names the recorded bypass actors" "$RK_BYPASS_ACTORS" "$rerun" \
'[.bypass_actors // [] | .[] | {actor_id, actor_type, bypass_mode}]
| sort_by(.actor_type, .actor_id, .bypass_mode) | tojson'
check "$id" "$trunk_name requires a pull request" true "$rerun" '[.rules[].type] | contains(["pull_request"])'
check "$id" "$trunk_name requires a status check" true "$rerun" '[.rules[].type] | contains(["required_status_checks"])'
check "$id" "$trunk_name allows only the squash merge" '["squash"]' \
'a merge commit or a rebase would take the trunk off its one linear history; '"$rerun" \
'[.rules[] | select(.type=="pull_request") | .parameters.allowed_merge_methods] | first // [] | sort | tojson'
if [ -n "${RK_REQUIRED_CHECK:-}" ]; then
owned="$(printf '%s\n%s\n' "$RK_REQUIRED_CHECK" "$RK_TITLE_CHECK" | sort | tr '\n' ',' | sed 's/,$//')"
check "$id" "$trunk_name requires the checks the setup owns" "$owned" "$rerun" \
'[.rules[] | select(.type=="required_status_checks") | .parameters.required_status_checks[].context] | sort | join(",")'
fi
check "$id" "$trunk_name asks for no approving review" 0 "$rerun" \
'[.rules[] | select(.type=="pull_request") | .parameters.required_approving_review_count] | first'
fi
sid="$(gh api "repos/$RK_REPO/rulesets" -q ".[] | select(.name == \"$safety_name\") | .id" | head -n 1)"
if [ -n "$sid" ]; then
rerun='rk setup step protect-trunk --apply'
check "$sid" "$safety_name names no bypass actor" 0 "$rerun" '.bypass_actors // [] | length'
check "$sid" "$safety_name refuses deletion and force-push" true "$rerun" \
'[.rules[].type] | sort == ["deletion","non_fast_forward"]'
check "$sid" "$safety_name covers the trunk alone" "[\"refs/heads/$RK_TRUNK_BRANCH\"]" "$rerun" \
'.conditions.ref_name.include | tojson'
fi
lid="$(gh api "repos/$RK_REPO/rulesets" -q ".[] | select(.name == \"$lines_name\") | .id" | head -n 1)"
if [ -n "$lid" ]; then
check "$lid" "$lines_name pins the lines" true 'rk setup step protect-release-lines --apply' \
'[.rules[].type] | contains(["deletion","non_fast_forward"])'
fi
[ "$status" -eq 0 ] || exit 1
echo 'ok protections-check'