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}"
: "${RK_MERGE_FORM:?rk sets this; run this script through rk setup}"
: "${RK_MERGE_METHODS:?rk sets this; run this script through rk setup}"
: "${RK_SAFETY_RULE_TYPES:?rk sets this; run this script through rk setup}"
: "${RK_TAG_PROTECTION:?rk sets this; run this script through rk setup}"
: "${RK_FORGE_GATE:?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
set -- "$trunk_name:protect-trunk" "$safety_name:protect-trunk"
if [ "$RK_TAG_PROTECTION" = true ]; then
set -- "$@" "$tags_name:protect-tags"
fi
for pair in "$@"; 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
if [ "$RK_TAG_PROTECTION" != true ]; then
extra="$(printf '%s\n' "$extra" | grep -vxF "$tags_name" || true)"
fi
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"])'
if [ "$RK_FORGE_GATE" = true ]; then
check "$id" "$trunk_name requires a status check" true "$rerun" '[.rules[].type] | contains(["required_status_checks"])'
else
check "$id" "$trunk_name requires no status check" false "$rerun" '[.rules[].type] | contains(["required_status_checks"])'
fi
check "$id" "$trunk_name allows only the $RK_MERGE_FORM merge" "$(printf '%s' "$RK_MERGE_METHODS" | tr -d ' ')" \
'any other merge method would take the trunk off its one linear history in the recorded merge form; '"$rerun" \
'[.rules[] | select(.type=="pull_request") | .parameters.allowed_merge_methods] | first // [] | sort | tojson'
if [ "$RK_FORGE_GATE" = true ] && [ -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" "$RK_SAFETY_RULE_TYPES" "$rerun" \
'[.rules[].type] | sort | tojson'
check "$sid" "$safety_name covers the trunk alone" "[\"refs/heads/$RK_TRUNK_BRANCH\"]" "$rerun" \
'.conditions.ref_name.include | tojson'
fi
if [ "$RK_MERGE_FORM" = rebase ]; then
allowed="$(gh api "repos/$RK_REPO" -q .allow_rebase_merge 2>/dev/null || echo unreadable)"
if [ "$allowed" = true ]; then
echo 'ok the repository allows rebase merges'
else
echo "FAIL the repository allows rebase merges: allow_rebase_merge reads ${allowed:-nothing}" >&2
echo 'remediation: rk setup step protect-trunk --apply' >&2
status=1
fi
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'