From d151422c2ccc46b86ec5e105d9e3290d375c6a19 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 3 Oct 2026 11:46:24 +0000 Subject: [PATCH] chore: add owner-only rulesets for branches and tags Two importable GitHub rulesets that restrict creation, updates, deletion and force-pushes on every branch and tag to the Repository admin role (the owner on this personal repository), plus an import guide listing what else gets blocked and the settings rulesets cannot cover. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01HpBMmLezKyK7FADYUBiPmx --- .github/rulesets/README.md | 48 +++++++++++++++++++++++ .github/rulesets/owner-only-branches.json | 20 ++++++++++ .github/rulesets/owner-only-tags.json | 20 ++++++++++ 3 files changed, 88 insertions(+) create mode 100644 .github/rulesets/README.md create mode 100644 .github/rulesets/owner-only-branches.json create mode 100644 .github/rulesets/owner-only-tags.json diff --git a/.github/rulesets/README.md b/.github/rulesets/README.md new file mode 100644 index 0000000..2c427af --- /dev/null +++ b/.github/rulesets/README.md @@ -0,0 +1,48 @@ +# Rulesets « propriétaire seul » + +Deux rulesets GitHub qui réservent toute écriture dans le dépôt au rôle **Repository admin**. Sur un dépôt personnel, ce rôle n'appartient qu'au propriétaire (Tromset). + +| Fichier | Cible | Effet pour tout autre acteur | +|---|---|---| +| `owner-only-branches.json` | toutes les branches | impossible de créer, pousser, fusionner une PR, supprimer ou forcer un push | +| `owner-only-tags.json` | tous les tags | impossible de créer, déplacer ou supprimer un tag, donc de publier une release sur un nouveau tag | + +La règle `non_fast_forward` (blocage des force-push) double `update`. Elle reste en place au cas où `update` serait assoupli plus tard. + +## Importer + +1. **Settings > Rules > Rulesets > New ruleset > Import a ruleset**, puis choisir `owner-only-branches.json`, vérifier et cliquer **Create**. +2. Recommencer avec `owner-only-tags.json`. +3. Ouvrir chaque ruleset et vérifier deux choses : le statut est **Active**, et la **Bypass list** contient **Repository admin** réglé sur **Always allow**. +4. Tester : pousser une branche jetable, puis la supprimer. + +Si l'import refuse l'acteur (« contains an invalid actor ») : + +1. Retirer le bloc `bypass_actors` du fichier, puis réimporter. +2. Ajouter l'exception à la main : **Bypass list > Add bypass > Repository admin > Always allow > Save changes**. + +Ne laissez jamais un ruleset actif sans cette exception. En cas de blocage, vous restez admin : **Settings > Rules > Rulesets**, puis passez le ruleset en **Disabled**. + +Quand vous fusionnez votre propre PR, GitHub peut proposer « Merge without waiting for requirements to be met (bypass rules) ». Cochez la case : c'est votre exception qui s'applique. + +## Ce qui sera aussi bloqué + +Les rulesets bloquent tout acteur qui n'est pas dans la liste d'exceptions, y compris les automatismes : + +- **Claude (Claude Code)**, qui pousse les branches `claude-code/*` et ouvre des PR. Selon le jeton qu'il utilise (celui de l'application ou le vôtre), il sera peut-être bloqué. Pour le garder : **Bypass list > Add bypass**, chercher « Claude », sélectionner l'application, puis **Always allow**. Testez ensuite une poussée de Claude. +- **GitHub Actions** pour les workflows qui poussent ou créent des tags avec `GITHUB_TOKEN`. Aucun workflow du dépôt ne le fait aujourd'hui. +- **Dependabot** et les **deploy keys** en écriture. Vous pouvez les ajouter à la liste d'exceptions si vous en avez besoin. + +## Ce qu'un ruleset ne peut pas empêcher + +Un ruleset ne limite que ceux qui ont déjà un accès en écriture. Vous êtes aujourd'hui le seul collaborateur. Comme le dépôt est public, les réglages suivants complètent la protection : + +- **Collaborateurs** (Settings > Collaborators) : n'y ajoutez personne. +- **Pull requests** (Settings > General > Features > Pull requests) : réglez la création sur **Collaborators only**. Ne décochez pas complètement les PR : cela masquerait aussi les vôtres et celles de Claude. Après ce réglage, vérifiez que Claude peut encore ouvrir une PR. +- **Issues** (Settings > General > Features > Issues) : réglez la création sur **Collaborators only**, ou désactivez les issues. +- **Wiki** : cochez « Restrict editing to collaborators only », ou désactivez le wiki s'il ne sert pas. Désactivez aussi **Projects** si vous ne l'utilisez pas. +- **Commentaires et réactions** (Settings > Moderation options > Interaction limits) : choisissez **Limit to repository collaborators**. La limite dure 6 mois au maximum, il faudra la renouveler. +- **Actions et forks** (Settings > Actions > General) : choisissez **Require approval for all external contributors** pour les workflows des PR venant de forks. N'utilisez pas de workflow `pull_request_target`. +- **Lecture, clonage et fork** : impossibles à bloquer sur un dépôt public. Le seul moyen est de passer le dépôt en privé (Settings > General > Danger Zone > Change visibility). Dans ce cas, les forks existants restent publics, les étoiles sont perdues, et sur GitHub Free les rulesets d'un dépôt privé demandent GitHub Pro. + +Sources : [rulesets](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/about-rulesets), [API des rulesets](https://docs.github.com/en/rest/repos/rules?apiVersion=2022-11-28#create-a-repository-ruleset), [exceptions](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/creating-rulesets-for-a-repository#granting-bypass-permissions-for-your-branch-or-tag-ruleset), [limites d'interaction](https://docs.github.com/en/communities/moderating-comments-and-conversations/limiting-interactions-in-your-repository), [accès aux PR](https://github.blog/changelog/2026-02-13-new-repository-settings-for-configuring-pull-request-access/). diff --git a/.github/rulesets/owner-only-branches.json b/.github/rulesets/owner-only-branches.json new file mode 100644 index 0000000..b95f02b --- /dev/null +++ b/.github/rulesets/owner-only-branches.json @@ -0,0 +1,20 @@ +{ + "name": "Owner only - all branches", + "target": "branch", + "enforcement": "active", + "conditions": { + "ref_name": { + "include": ["~ALL"], + "exclude": [] + } + }, + "rules": [ + { "type": "creation" }, + { "type": "update", "parameters": { "update_allows_fetch_and_merge": false } }, + { "type": "deletion" }, + { "type": "non_fast_forward" } + ], + "bypass_actors": [ + { "actor_id": 5, "actor_type": "RepositoryRole", "bypass_mode": "always" } + ] +} diff --git a/.github/rulesets/owner-only-tags.json b/.github/rulesets/owner-only-tags.json new file mode 100644 index 0000000..fa1de6c --- /dev/null +++ b/.github/rulesets/owner-only-tags.json @@ -0,0 +1,20 @@ +{ + "name": "Owner only - all tags", + "target": "tag", + "enforcement": "active", + "conditions": { + "ref_name": { + "include": ["~ALL"], + "exclude": [] + } + }, + "rules": [ + { "type": "creation" }, + { "type": "update", "parameters": { "update_allows_fetch_and_merge": false } }, + { "type": "deletion" }, + { "type": "non_fast_forward" } + ], + "bypass_actors": [ + { "actor_id": 5, "actor_type": "RepositoryRole", "bypass_mode": "always" } + ] +}