1
0
mirror of git://f0xx.org/android_cast synced 2026-07-29 06:39:09 +03:00

gitea sync

This commit is contained in:
Anton Afanasyeu
2026-06-11 10:41:44 +02:00
parent 57f0e8b465
commit 88ca1b9e70
4 changed files with 284 additions and 1 deletions

View File

@@ -331,6 +331,40 @@ GITEA_SUBMODULES_CONF=/root/my-submodules.list sudo ./gitea_mirror_submodules.sh
sudo -u gitea gitea -c /var/lib/gitea/custom/conf/app.ini admin repo-sync-mirrors
```
## Branch protection (`master`, `next` only)
Server-side rules per [docs/GIT_FLOW.md](../../../../docs/GIT_FLOW.md) §7. **Two places:**
| Where | Tool |
|-------|------|
| **Gitea** `AndroidCast/android_cast` | `gitea_protect_branches.sh` |
| **Canonical FE** `git://10.7.0.10/android_cast` | `examples/git/hooks/pre-receive.android_cast.example` |
**Gitea (BE):**
```bash
sudo ./examples/crash_reporter/backend/scripts/gitea/gitea_protect_branches.sh
sudo ./examples/crash_reporter/backend/scripts/gitea/gitea_protect_branches.sh --list
```
- `master` and `next` only (no `*` wildcard — `feature/*` stays free)
- Force-push **disabled for everyone**
- Push/merge allowlist: **admin**, **foxx**, org team **Owners**
- Admins cannot bypass merge rules
**FE bare repo** (primary enforcement for `git push origin`):
```bash
# on FE, in bare repo hooks/
cp examples/git/hooks/pre-receive.android_cast.example \
/path/to/android_cast.git/hooks/pre-receive
chmod +x /path/to/android_cast.git/hooks/pre-receive
```
Rejects on `master` / `next`: branch delete, non-fast-forward (force-push). Other branches unchanged.
`gitea_polish_project.sh` runs branch protection automatically unless `GITEA_SKIP_BRANCH_PROTECT=1`.
## Polish (finish line — safe BE run)
```bash

View File

@@ -200,7 +200,12 @@ if command -v "$SCRIPT_DIR/gitea_set_default_branch.sh" >/dev/null 2>&1; then
sh "$SCRIPT_DIR/gitea_set_default_branch.sh" || warn "default branch set failed (sync first)"
fi
# 7) Summary
# 7) Branch protection (master, next)
if [ "${GITEA_SKIP_BRANCH_PROTECT:-0}" -eq 0 ]; then
sh "$SCRIPT_DIR/gitea_protect_branches.sh" || warn "branch protection failed — run manually"
fi
# 8) Summary
log "=== done ==="
cat <<EOF
@@ -208,6 +213,8 @@ UI checklist:
• foxx/admin: open ${GITEA_ROOT_URL%/}/$GITEA_ORG (org page — not only "Your repositories")
• Expect: android_cast, libvpx, opus, speex under $GITEA_ORG
• If android_cast still stale: sudo ./gitea_diagnose_mirror_sync.sh
• Branch protection: master/next on Gitea; install FE hook:
examples/git/hooks/pre-receive.android_cast.example
• Email/2FA later: app.ini REGISTER_EMAIL_CONFIRM=false; add SMTP when ready
EOF

View File

@@ -0,0 +1,172 @@
#!/bin/ash
#
# Server-side protection for master and next on Gitea (android_cast).
# Blocks force-push for everyone; push/merge limited to org Owners (admin, foxx).
# Side branches (feature/*, fix/*) are unaffected — no wildcard rule.
#
# Usage (BE as root):
# sudo ./gitea_protect_branches.sh
# GITEA_OWNER=AndroidCast GITEA_REPO=android_cast sudo ./gitea_protect_branches.sh
# sudo ./gitea_protect_branches.sh --list
#
# Note: canonical git on FE (git://10.7.0.10/android_cast) needs its own hook —
# see examples/git/hooks/pre-receive.android_cast.example
#
set -eu
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# shellcheck source=gitea_ini.sh
. "$SCRIPT_DIR/gitea_ini.sh"
# shellcheck source=gitea_mirror_lib.sh
. "$SCRIPT_DIR/gitea_mirror_lib.sh"
GITEA_OWNER="${GITEA_OWNER:-${GITEA_ORG:-AndroidCast}}"
GITEA_REPO="${GITEA_REPO:-android_cast}"
# Space-separated branches to protect (exact names only).
GITEA_PROTECT_BRANCHES="${GITEA_PROTECT_BRANCHES:-master next}"
# Users allowed to push (fast-forward / merge) to protected branches.
GITEA_PROTECT_PUSH_USERS="${GITEA_PROTECT_PUSH_USERS:-admin foxx}"
# Org team with push access (AndroidCast Owners).
GITEA_PROTECT_PUSH_TEAM="${GITEA_PROTECT_PUSH_TEAM:-Owners}"
log() { printf '[gitea-protect] %s\n' "$*"; }
warn() { printf '[gitea-protect] WARN: %s\n' "$*" >&2; }
die() { printf '[gitea-protect] ERROR: %s\n' "$*" >&2; exit 1; }
gitea_api_token() {
_t="${GITEA_ADMIN_TOKEN:-}"
[ -n "$_t" ] || _t="$(gitea_resolve_push_token)" || return 1
printf '%s' "$_t"
}
gitea_list_branch_protections() {
command -v curl >/dev/null 2>&1 || return 1
_token="$(gitea_api_token)" || return 1
_api="$(gitea_api_base)"
curl -sS "$_api/repos/$GITEA_OWNER/$GITEA_REPO/branch_protections" \
-H "Authorization: token $_token"
}
gitea_protection_exists() {
_branch="$1"
gitea_list_branch_protections 2>/dev/null | grep -q "\"branch_name\":\"$_branch\""
}
gitea_protect_payload() {
_branch="$1"
_prio="$2"
_users_json=""
for _u in $GITEA_PROTECT_PUSH_USERS; do
[ -n "$_u" ] || continue
_users_json="$_users_json\"$_u\","
done
_users_json="${_users_json%,}"
cat <<EOF
{
"rule_name": "$_branch",
"branch_name": "$_branch",
"priority": $_prio,
"enable_push": true,
"enable_push_whitelist": true,
"push_whitelist_usernames": [$_users_json],
"push_whitelist_teams": ["$GITEA_PROTECT_PUSH_TEAM"],
"enable_force_push": false,
"enable_force_push_allowlist": false,
"block_admin_merge_override": true
}
EOF
}
gitea_apply_protection() {
_branch="$1"
_prio="$2"
command -v curl >/dev/null 2>&1 || return 1
_token="$(gitea_api_token)" || return 1
_api="$(gitea_api_base)"
_payload="$(gitea_protect_payload "$_branch" "$_prio")"
_resp="$(mktemp /tmp/gitea-protect-XXXXXX.json)"
if gitea_protection_exists "$_branch"; then
log "update protection: $GITEA_OWNER/$GITEA_REPO::$_branch"
_http="$(curl -sS -o "$_resp" -w '%{http_code}' \
-X PATCH "$_api/repos/$GITEA_OWNER/$GITEA_REPO/branch_protections/$_branch" \
-H "Authorization: token $_token" \
-H "Content-Type: application/json" \
-d "$_payload")"
else
log "create protection: $GITEA_OWNER/$GITEA_REPO::$_branch"
_http="$(curl -sS -o "$_resp" -w '%{http_code}' \
-X POST "$_api/repos/$GITEA_OWNER/$GITEA_REPO/branch_protections" \
-H "Authorization: token $_token" \
-H "Content-Type: application/json" \
-d "$_payload")"
fi
case "$_http" in
200|201|204) gitea_rm_path "$_resp"; return 0 ;;
*)
warn "HTTP $_http for $_branch:"
head -c 500 "$_resp" >&2 2>/dev/null || true
printf '\n' >&2
gitea_rm_path "$_resp"
return 1
;;
esac
}
list_protections() {
gitea_load_config || exit 1
gitea_ensure_cli_access || exit 1
log "branch protections: $GITEA_OWNER/$GITEA_REPO"
gitea_list_branch_protections | tr ',' '\n' | grep -E 'branch_name|enable_force_push|enable_push' || true
}
# --- main ---
case "${1:-}" in
-h|--help|help)
sed -n '2,16p' "$0"
exit 0
;;
--list|list)
list_protections
exit 0
;;
esac
gitea_load_config || exit 1
gitea_ensure_cli_access || exit 1
if ! gitea_repo_exists_api "$GITEA_OWNER" "$GITEA_REPO"; then
die "repo $GITEA_OWNER/$GITEA_REPO not found — run gitea_polish_project.sh first"
fi
log "repo=$GITEA_OWNER/$GITEA_REPO branches=$GITEA_PROTECT_BRANCHES"
log "push allowlist: users=$GITEA_PROTECT_PUSH_USERS team=$GITEA_PROTECT_PUSH_TEAM"
log "force-push: disabled for all | side branches: unprotected"
_prio=1
_fail=0
for _b in $GITEA_PROTECT_BRANCHES; do
gitea_apply_protection "$_b" "$_prio" || _fail=1
_prio=$((_prio + 1))
done
cat <<EOF
Gitea rules applied. Verify in UI:
$GITEA_OWNER/$GITEA_REPO → Settings → Branches
Protected: master, next only
• No force-push (anyone)
• Push/merge: $GITEA_PROTECT_PUSH_USERS + team $GITEA_PROTECT_PUSH_TEAM
• Admins cannot bypass (block_admin_merge_override)
IMPORTANT — canonical origin on FE is separate:
Install examples/git/hooks/pre-receive.android_cast.example on the bare repo
at git://10.7.0.10/android_cast (hooks/pre-receive).
EOF
[ "$_fail" -eq 0 ]