Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/rulesets/main-protection.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "ARStack Main - Pull Requests and Naming CI",
"target": "branch",
"enforcement": "active",
"conditions": {
"ref_name": {
"include": [
"refs/heads/main"
],
"exclude": []
}
},
"rules": [
{
"type": "deletion"
},
{
"type": "non_fast_forward"
},
{
"type": "pull_request",
"parameters": {
"dismiss_stale_reviews_on_push": true,
"require_code_owner_review": false,
"require_last_push_approval": false,
"required_approving_review_count": 0,
"required_review_thread_resolution": true
}
},
{
"type": "required_status_checks",
"parameters": {
"strict_required_status_checks_policy": true,
"required_status_checks": [
{
"context": "tracked-tree-names"
}
]
}
}
]
}
27 changes: 27 additions & 0 deletions docs/MAINTAINER_MAIN_PROTECTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Protect the public `main` branch

ARStack's public releases come from reviewed `main`. Keeping merges on PRs protects the working downloads, documentation and tested runtime.

The recommended main ruleset is checked into the repository as [`.github/rulesets/main-protection.json`](../.github/rulesets/main-protection.json). It prevents branch deletion and force-pushes, requires a pull request, requires resolved review discussions, and requires the universal **Product Naming Guard / tracked-tree-names** check against the latest `main` revision.

The approving-review count is **zero** for a solo-maintainer open-source repository: the PR and required automated check remain mandatory without requiring an outside reviewer for every documentation change. Runtime and installer changes should also show their relevant C++/Qt/package CI green before merge.

## Activate (repository administrator)

Using the [GitHub CLI](https://cli.github.com/) authenticated with repository administration permission:

```bash
bash scripts/apply_main_ruleset.sh --dry-run
bash scripts/apply_main_ruleset.sh --apply
```

The script updates a ruleset of the same name or creates it once, then prints GitHub's resulting ruleset. Alternatively, go to **Settings → Rules → Rulesets → New branch ruleset** and apply the JSON equivalent.

After activation, confirm:

1. **Settings → Rules → Rulesets** lists `ARStack Main - Pull Requests and Naming CI` as active.
2. A direct push to `main` is refused and new changes go through PRs.
3. A PR without a successful `tracked-tree-names` check cannot merge.
4. A PR built against an outdated `main` must update before merging.

**Connector access:** The GitHub integration permits source, PR and CI changes but rejects branch-protection administration (HTTP 403). Merely storing this JSON does not turn GitHub protection on; it must be applied by an authorized administrator. Historical release tags and verified binaries are unaffected.
29 changes: 29 additions & 0 deletions scripts/apply_main_ruleset.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
# Apply the reviewed, repo-owned main ruleset using an administrator's GitHub CLI session.
set -euo pipefail
repo='masarray/arstack61850'
name='ARStack Main - Pull Requests and Naming CI'
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
manifest="$root/.github/rulesets/main-protection.json"
python3 -m json.tool "$manifest" >/dev/null
case "${1:---dry-run}" in
--dry-run)
echo "Ruleset validated. This command has not changed GitHub settings."
echo "To activate as a repository admin: bash scripts/apply_main_ruleset.sh --apply"
exit 0
;;
--apply) ;;
*) echo 'Usage: bash scripts/apply_main_ruleset.sh [--dry-run|--apply]' >&2; exit 2;;
esac
command -v gh >/dev/null || { echo 'GitHub CLI is required: https://cli.github.com/' >&2; exit 1; }
gh auth status >/dev/null
existing="$(gh api "repos/$repo/rulesets" --jq '.[] | select(.name == "ARStack Main - Pull Requests and Naming CI") | .id' | head -n1)"
if [ -n "$existing" ]; then
gh api --method PUT "repos/$repo/rulesets/$existing" --input "$manifest" >/dev/null
echo "Updated active main ruleset ID: $existing"
else
gh api --method POST "repos/$repo/rulesets" --input "$manifest" >/dev/null
echo "Created active main ruleset."
fi
gh api "repos/$repo/rulesets" --jq '.[] | select(.name == "ARStack Main - Pull Requests and Naming CI") | {id,name,enforcement}'
echo 'Confirm on GitHub: Settings > Rules > Rulesets'
Loading