repowarden 4.3.0-next.4 → 4.3.0-next.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/proteger +24 -5
- package/hooks/commit-msg +23 -0
- package/hooks/lib/common.sh +22 -0
- package/hooks/lib/i18n/en.sh +9 -0
- package/hooks/lib/i18n/fr.sh +9 -0
- package/package.json +1 -1
package/bin/proteger
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
# [--sans-tags] [--dry-run]
|
|
15
15
|
# --sans-tags : dépôt qui déplace lui-même un tag (tag majeur flottant v2…).
|
|
16
16
|
# Réglages équivalents dans .repowarden.conf (requiredReviews, codeOwnerReview,
|
|
17
|
-
# unattributedApproval, environment, environmentReviewers). Demande un gh connecté, admin du dépôt.
|
|
17
|
+
# unattributedApproval, deliveryApproval, environment, environmentReviewers). Demande un gh connecté, admin du dépôt.
|
|
18
18
|
set -euo pipefail
|
|
19
19
|
|
|
20
20
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
|
|
@@ -94,7 +94,8 @@ refs_json() { # branches → "refs/heads/a", "refs/heads/b"
|
|
|
94
94
|
|
|
95
95
|
# Ruleset de branches : $1 nom, $2 branches (liste), $3 méthodes de merge (JSON),
|
|
96
96
|
# $4 PR à jour exigée (défaut true), $5 approbations (défaut REVIEWS),
|
|
97
|
-
# $6 dernier push approuvé par un autre (défaut selon REVIEWS)
|
|
97
|
+
# $6 dernier push approuvé par un autre (défaut selon REVIEWS),
|
|
98
|
+
# $7 règle supplémentaire (JSON), ex. déploiement réussi exigé
|
|
98
99
|
branch_ruleset() {
|
|
99
100
|
# shellcheck disable=SC2086 # liste de branches volontairement découpée
|
|
100
101
|
cat <<JSON
|
|
@@ -118,7 +119,8 @@ branch_ruleset() {
|
|
|
118
119
|
{"type": "required_status_checks", "parameters": {
|
|
119
120
|
"strict_required_status_checks_policy": ${4:-true},
|
|
120
121
|
"do_not_enforce_on_create": false,
|
|
121
|
-
"required_status_checks": [$contexts]}}
|
|
122
|
+
"required_status_checks": [$contexts]}}${7:+,
|
|
123
|
+
$7}
|
|
122
124
|
]
|
|
123
125
|
}
|
|
124
126
|
JSON
|
|
@@ -161,12 +163,25 @@ if [ -n "$integration" ]; then
|
|
|
161
163
|
# le mainteneur peut donc l'approuver), sans exiger un autre approbateur
|
|
162
164
|
# que l'auteur du dernier push sauf si des relectures sont configurées
|
|
163
165
|
livraison=$((REVIEWS > 0 ? REVIEWS : 1))
|
|
166
|
+
# deliveryApproval = deployment (défaut) : la validation humaine est
|
|
167
|
+
# l'approbation de l'environnement de livraison (« Approve and deploy »),
|
|
168
|
+
# exigée par une règle de main (déploiement réussi) ; la revue de PR n'est
|
|
169
|
+
# plus nécessaire (relectures configurées : gardées). review : revue de PR.
|
|
170
|
+
cfg_r deliveryApproval deployment
|
|
171
|
+
DELIVERY="$REPLY"
|
|
172
|
+
[[ "$DELIVERY" =~ ^(deployment|review)$ ]] || { err_t ci.proteger.delivery_invalid; exit 1; }
|
|
173
|
+
deploiement=""
|
|
174
|
+
if [ "$DELIVERY" = deployment ]; then
|
|
175
|
+
ENVIRONMENT="${ENVIRONMENT:-production}"
|
|
176
|
+
livraison="$REVIEWS"
|
|
177
|
+
deploiement="{\"type\": \"required_deployments\", \"parameters\": {\"required_deployment_environments\": [\"$ENVIRONMENT\"]}}"
|
|
178
|
+
fi
|
|
164
179
|
# PR à jour non exigée non plus : le merge commit d'une livraison n'existe
|
|
165
180
|
# que sur main ; strict, la livraison suivante serait bloquée tant que
|
|
166
181
|
# develop ne l'a pas reçu (retour main → develop vide après chaque
|
|
167
182
|
# release). Une livraison n'apporte que develop, vérifiée par la CI ; le
|
|
168
183
|
# retour reste fait quand main a un contenu propre (correctif direct).
|
|
169
|
-
[ -z "$others" ] || rulesets+=("$(branch_ruleset repowarden "$others" '"merge"' false "$livraison" "$last_push")")
|
|
184
|
+
[ -z "$others" ] || rulesets+=("$(branch_ruleset repowarden "$others" '"merge"' false "$livraison" "$last_push" "$deploiement")")
|
|
170
185
|
# Branche d'intégration : PR à jour non exigée. Le retour de main (après
|
|
171
186
|
# une release) serait sinon presque toujours en retard, et « mettre à jour »
|
|
172
187
|
# fusionnerait develop dans main en contournant la livraison ; la CI
|
|
@@ -215,7 +230,11 @@ echo_t ci.proteger.1 "$REPO"
|
|
|
215
230
|
echo_t ci.proteger.2 "$existing"
|
|
216
231
|
echo_t ci.proteger.3 "$CHECKS"
|
|
217
232
|
echo_t ci.proteger.4 "$methods" "$delete_on_merge"
|
|
218
|
-
[ -
|
|
233
|
+
if [ -n "$integration" ] && [ "$DELIVERY" = deployment ]; then
|
|
234
|
+
echo_t ci.proteger.delivery_deploy "$ENVIRONMENT" "$auto_merge"
|
|
235
|
+
elif [ -n "$integration" ]; then
|
|
236
|
+
echo_t ci.proteger.delivery "$livraison" "$auto_merge"
|
|
237
|
+
fi
|
|
219
238
|
echo_t ci.proteger.5 "$tags_msg"
|
|
220
239
|
[ -z "$integration" ] || echo_t ci.proteger.6 "$integration"
|
|
221
240
|
echo_t ci.proteger.7 "$REVIEWS" "$CODEOWNERS" "$UNATTRIBUTED"
|
package/hooks/commit-msg
CHANGED
|
@@ -8,6 +8,29 @@ exit_if_skipped
|
|
|
8
8
|
run_local_hook "$@"
|
|
9
9
|
|
|
10
10
|
MSG_FILE="$1"
|
|
11
|
+
|
|
12
|
+
# Agents IA : signatures retirées du message, identité d'agent refusée
|
|
13
|
+
if agents_refused; then
|
|
14
|
+
agent_lines_r "$(cat "$MSG_FILE")"
|
|
15
|
+
if [ -n "$REPLY" ]; then
|
|
16
|
+
while IFS= read -r ligne; do attention_t hook.agent_stripped "$ligne"; done <<<"$REPLY"
|
|
17
|
+
# grep -a : texte même avec un emoji (Windows le croirait binaire) ;
|
|
18
|
+
# contenu réécrit dans le même fichier (git le garde ouvert sous Windows)
|
|
19
|
+
filtre="$(LC_ALL=C grep -aviE "$AGENT_LINE_ERE" "$MSG_FILE" || true)"
|
|
20
|
+
printf '%s\n' "$filtre" >"$MSG_FILE"
|
|
21
|
+
fi
|
|
22
|
+
for ident in GIT_AUTHOR_IDENT GIT_COMMITTER_IDENT; do
|
|
23
|
+
id="$(git var "$ident" 2>/dev/null || true)"
|
|
24
|
+
nom="${id%% <*}"
|
|
25
|
+
mail="${id#*<}"
|
|
26
|
+
mail="${mail%%>*}"
|
|
27
|
+
if agent_identity "$nom" "$mail"; then
|
|
28
|
+
err_t hook.agent_identity "$nom <$mail>"
|
|
29
|
+
echo_t hook.agent_identity_fix
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
done
|
|
33
|
+
fi
|
|
11
34
|
# Première ligne non commentée
|
|
12
35
|
SUBJECT="$(grep -v '^#' "$MSG_FILE" | sed -n 1p)"
|
|
13
36
|
|
package/hooks/lib/common.sh
CHANGED
|
@@ -169,6 +169,28 @@ persistent_pr_r() {
|
|
|
169
169
|
esac
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
# Agents IA (code écrit pour quelqu'un) : ni auteur ni committer d'un commit,
|
|
173
|
+
# ni signature dans un message (Co-Authored-By, « Generated with »). Les bots
|
|
174
|
+
# d'automatisation (github-actions, App repowarden, Dependabot) ne sont pas
|
|
175
|
+
# concernés. Réglage allowAgentSignatures = true pour les autoriser.
|
|
176
|
+
AGENT_EMAIL_RE='^(noreply@anthropic\.com|[0-9]+\+[Cc]opilot@users\.noreply\.github\.com|cursoragent@cursor\.com|devin-ai-integration\[bot\]@users\.noreply\.github\.com)$'
|
|
177
|
+
AGENT_NAME_RE='^(Claude|Claude Code|Copilot|Cursor Agent|Devin AI)$'
|
|
178
|
+
# Lignes de signature (grep -iE, insensible à la casse)
|
|
179
|
+
# (locale C : un emoji en tête de ligne, comme « 🤖 Generated with », reste
|
|
180
|
+
# des octets quelconques, y compris sous Windows ; motifs en ASCII)
|
|
181
|
+
AGENT_LINE_ERE='(^[[:space:]]*co-authored-by:.*(anthropic\.com|copilot@users\.noreply\.github\.com|cursor\.com|devin-ai-integration))|(generated (with|by) \[?(claude|github copilot|copilot|cursor|devin))'
|
|
182
|
+
|
|
183
|
+
# Vrai si les signatures d'agents sont refusées (défaut)
|
|
184
|
+
agents_refused() { cfg_r allowAgentSignatures false; [ "$REPLY" != true ]; }
|
|
185
|
+
|
|
186
|
+
# Vrai si l'identité $1 (nom) / $2 (e-mail) est celle d'un agent IA
|
|
187
|
+
agent_identity() { [[ "$2" =~ $AGENT_EMAIL_RE || "$1" =~ $AGENT_NAME_RE ]]; }
|
|
188
|
+
|
|
189
|
+
# REPLY = premières lignes de signature d'agent du texte $1 (vide si aucune)
|
|
190
|
+
agent_lines_r() {
|
|
191
|
+
REPLY="$(LC_ALL=C grep -aiE "$AGENT_LINE_ERE" <<<"$1" || true)"
|
|
192
|
+
}
|
|
193
|
+
|
|
172
194
|
# Vrai si $1 est un en-tête conforme (format et 72 caractères)
|
|
173
195
|
header_valid() {
|
|
174
196
|
[[ "$1" =~ $CC_PATTERN ]] || return 1
|
package/hooks/lib/i18n/en.sh
CHANGED
|
@@ -231,6 +231,13 @@ _msg_en() {
|
|
|
231
231
|
ci.check.25) _M="Disabled by .repowarden.conf (skip %s)." ;;
|
|
232
232
|
ci.check.26) _M="Failed:%s" ;;
|
|
233
233
|
ci.check.27) _M="All repowarden checks passed." ;;
|
|
234
|
+
hook.agent_stripped) _M="AI agent signature removed from the message: %s" ;;
|
|
235
|
+
hook.agent_identity) _M="Commit refused: the author or committer is an AI agent (%s). Commits carry a person's identity." ;;
|
|
236
|
+
hook.agent_identity_fix) _M=" Fix: git config user.name \"Your Name\" && git config user.email you@mail, then commit again. To allow agents: git config repowarden.allowAgentSignatures true" ;;
|
|
237
|
+
ci.check.agent_identity) _M="Commit %s: AI agent author or committer (%s); commits carry a person's identity." ;;
|
|
238
|
+
ci.check.agent_line) _M="Commit %s: AI agent signature in the message (%s)." ;;
|
|
239
|
+
ci.check.agent_pr_body) _M="PR description: AI agent signature (%s); it would become the commit message when squashing, remove it." ;;
|
|
240
|
+
ci.check.agent_fix) _M="Rewrite the affected commits with a person's identity, without agent signature (setting repowarden.allowAgentSignatures = true to allow them)." ;;
|
|
234
241
|
ci.check.inverted) _M="PR from \"%s\" to \"%s\": a persistent branch only goes out for a delivery (develop → main) or a back-merge (main → develop). Pointless PR: nothing to check, it is closed automatically." ;;
|
|
235
242
|
ci.check.inverted_fix) _M="To update a work branch: on that branch, git merge origin/%s, then git push." ;;
|
|
236
243
|
ci.check.back_merge) _M="Back-merge of %s into %s (merge commit): the PR title is not checked." ;;
|
|
@@ -263,6 +270,8 @@ _msg_en() {
|
|
|
263
270
|
ci.proteger.13) _M="Settings applied." ;;
|
|
264
271
|
ci.proteger.reviews_invalid) _M="--relecteurs: a number from 0 to 9 is expected." ;;
|
|
265
272
|
ci.proteger.codeowners_invalid) _M="codeOwnerReview: true or false." ;;
|
|
273
|
+
ci.proteger.delivery_deploy) _M=" delivery into main: approval of the \"%s\" deployment (Approve and deploy), then merged by the GitHub App; auto-merge of work PRs into develop: %s" ;;
|
|
274
|
+
ci.proteger.delivery_invalid) _M="deliveryApproval: deployment or review." ;;
|
|
266
275
|
ci.proteger.automerge_invalid) _M="autoMergeWork: true or false." ;;
|
|
267
276
|
ci.proteger.unattributed_invalid) _M="unattributedApproval: true or false." ;;
|
|
268
277
|
ci.proteger.no_branch) _M="None of the branches \"%s\" exists on %s." ;;
|
package/hooks/lib/i18n/fr.sh
CHANGED
|
@@ -231,6 +231,13 @@ _msg_fr() {
|
|
|
231
231
|
ci.check.25) _M="Désactivé par .repowarden.conf (skip %s)." ;;
|
|
232
232
|
ci.check.26) _M="Échec :%s" ;;
|
|
233
233
|
ci.check.27) _M="Toutes les vérifications repowarden sont passées." ;;
|
|
234
|
+
hook.agent_stripped) _M="Signature d'agent IA retirée du message : %s" ;;
|
|
235
|
+
hook.agent_identity) _M="Commit refusé : l'auteur ou le committer est un agent IA (%s). Les commits portent l'identité d'une personne." ;;
|
|
236
|
+
hook.agent_identity_fix) _M=" Corriger : git config user.name \"Ton Nom\" && git config user.email ton@mail, puis recommencer le commit. Pour autoriser les agents : git config repowarden.allowAgentSignatures true" ;;
|
|
237
|
+
ci.check.agent_identity) _M="Commit %s : auteur ou committer agent IA (%s) ; les commits portent l'identité d'une personne." ;;
|
|
238
|
+
ci.check.agent_line) _M="Commit %s : signature d'agent IA dans le message (%s)." ;;
|
|
239
|
+
ci.check.agent_pr_body) _M="Description de la PR : signature d'agent IA (%s) ; elle deviendrait le message du commit en squash, à retirer." ;;
|
|
240
|
+
ci.check.agent_fix) _M="Réécrire les commits concernés avec l'identité d'une personne, sans signature d'agent (réglage repowarden.allowAgentSignatures = true pour les autoriser)." ;;
|
|
234
241
|
ci.check.inverted) _M="PR de « %s » vers « %s » : une branche persistante ne part que pour une livraison (develop → main) ou un retour (main → develop). PR sans objet : rien à vérifier, elle est fermée automatiquement." ;;
|
|
235
242
|
ci.check.inverted_fix) _M="Pour mettre une branche de travail à jour : sur cette branche, git merge origin/%s, puis git push." ;;
|
|
236
243
|
ci.check.back_merge) _M="Retour de %s dans %s (merge commit) : le titre de la PR n'est pas vérifié." ;;
|
|
@@ -263,6 +270,8 @@ _msg_fr() {
|
|
|
263
270
|
ci.proteger.13) _M="Réglages appliqués." ;;
|
|
264
271
|
ci.proteger.reviews_invalid) _M="--relecteurs : nombre de 0 à 9 attendu." ;;
|
|
265
272
|
ci.proteger.codeowners_invalid) _M="codeOwnerReview : true ou false." ;;
|
|
273
|
+
ci.proteger.delivery_deploy) _M=" livraison vers main : approbation du déploiement « %s » (Approve and deploy), puis merge par la GitHub App ; merge automatique des PR de travail vers develop : %s" ;;
|
|
274
|
+
ci.proteger.delivery_invalid) _M="deliveryApproval : deployment ou review." ;;
|
|
266
275
|
ci.proteger.automerge_invalid) _M="autoMergeWork : true ou false." ;;
|
|
267
276
|
ci.proteger.unattributed_invalid) _M="unattributedApproval : true ou false." ;;
|
|
268
277
|
ci.proteger.no_branch) _M="Aucune des branches « %s » n'existe sur %s." ;;
|
package/package.json
CHANGED