diff options
| author | Leitwolf11 | 2026-11-13 01:57:15 +0300 |
|---|---|---|
| committer | Leitwolf11 | 2026-11-13 01:57:15 +0300 |
| commit | 05d42b1a4ca923ee7726c35c261bfc75d32ddea3 (patch) | |
| tree | b7f2ddce7130aca707d9b9a5d9844078230812e5 /ops | |
| parent | 83e0ad4586d90bf02c3a5bfeb1ab92fd90e51703 (diff) | |
| download | progmaweb-ops/git-mirrors.tar.gz | |
Serve only listed mirrors and report a failed default-branch lookupops/git-mirrors
- git-http-backend no longer exports every directory under the mirror
root: GIT_HTTP_EXPORT_ALL is gone, git-mirror marks each listed mirror
with git-daemon-export-ok, and a mirror taken off the list loses the
mark and is deleted on the next run. Tried live: an unlisted bare
repository answered 404 and was removed by the next run.
- git-mirror checks git ls-remote before it reads the default branch
and fails the run when the lookup fails.
- The README explains the /usr/bin spelling of the fcgiwrap label (an
equivalence of /usr/sbin), the stock label of /srv/*/www, and where
the DNS record is kept.
Diffstat (limited to 'ops')
| -rw-r--r-- | ops/README.md | 10 | ||||
| -rw-r--r-- | ops/git/git-mirror.sh | 26 | ||||
| -rw-r--r-- | ops/git/nginx/git.conf | 2 |
3 files changed, 32 insertions, 6 deletions
diff --git a/ops/README.md b/ops/README.md index 9022227..285b2ba 100644 --- a/ops/README.md +++ b/ops/README.md @@ -320,7 +320,9 @@ Packages: `git-core`, and `cgit` and `fcgiwrap` from EPEL; `checkpolicy` builds - **Mirrors.** `git-mirror` fetches only branches and tags from `https://github.com/Progmasoft/<name>.git` (never the pull-request refs), prunes what GitHub removed, follows its default branch, and repacks into one pack with a bitmap when something changed, so a clone starts sending at once. It needs no credentials. A new repository needs a line in - `repositories` and a `repo.url` block in `cgitrc`. + `repositories` and a `repo.url` block in `cgitrc`. git-http-backend serves only the mirrors `git-mirror` marks with + `git-daemon-export-ok`; a mirror taken off `repositories` loses the mark and is deleted on the next run, so a + repository that becomes private or archived stops being cloned within ten minutes. - **Read only.** Nginx answers 403 to `git-receive-pack` and to the dumb protocol; git-http-backend gets no user; the mirrors belong to `gitmirror` and are read as `cgit`, trusted through `safe.directory` for that backend only. - **SELinux.** `/srv/git/mirrors` is `git_sys_content_t` and `/var/cache/cgit` `git_rw_content_t` (package default). @@ -331,14 +333,18 @@ Packages: `git-core`, and `cgit` and `fcgiwrap` from EPEL; `checkpolicy` builds ```sh semanage fcontext -a -t git_sys_content_t '/srv/git/mirrors(/.*)?' semanage fcontext -a -t bin_t /usr/local/libexec/git-mirror + # /usr/sbin is an equivalence of /usr/bin, so semanage takes the /usr/bin spelling; restorecon on + # /usr/sbin/fcgiwrap then gives it httpd_exec_t (check with ls -Z). semanage fcontext -a -t httpd_exec_t /usr/bin/fcgiwrap semanage fcontext -a -t git_script_exec_t /usr/libexec/git-core/git-http-backend restorecon -RF /srv/git /usr/local/libexec/git-mirror /usr/sbin/fcgiwrap /usr/libexec/git-core/git-http-backend ``` + `/srv/git/www/static` needs no rule of its own: the stock policy labels `/srv/*/www` `httpd_sys_content_t`. - **No Cloudflare proxy.** `git.progmasoft.com` is a DNS-only A record: through the proxy, a clone of a large repository (catch3, about 25 MB) never reached the client, while the origin served it in under a minute. The address of the server - is public through `mail.progmasoft.com` anyway; Nginx limits requests and connections per address itself. + is public through `mail.progmasoft.com` anyway; Nginx limits requests and connections per address itself. The record + is in `cloudflarectl/config.progmasoft.json`. - **Look.** No README is rendered (cgit would include its HTML unfiltered) and no script runs: the content security policy allows none, and Nginx removes the inline `onchange` handlers of cgit's menus, whose buttons do the same. - **Certificate.** The certificate of `progmasoft.com` names `git.progmasoft.com` (webroot, `--expand`). diff --git a/ops/git/git-mirror.sh b/ops/git/git-mirror.sh index 25bed02..a36f978 100644 --- a/ops/git/git-mirror.sh +++ b/ops/git/git-mirror.sh @@ -40,9 +40,16 @@ for name in $names; do git -C "$repository" repack -a -d -b -q touch "$repository/info/web/repacked" fi - # HEAD follows the default branch of GitHub. - head=$(git -C "$repository" ls-remote --symref origin HEAD | sed -n 's|^ref: refs/heads/\([^[:space:]]*\)[[:space:]]*HEAD$|\1|p') - [ -n "$head" ] && git -C "$repository" symbolic-ref HEAD "refs/heads/$head" + # HEAD follows the default branch of GitHub; a failed lookup fails the run. + if advertised=$(git -C "$repository" ls-remote --symref origin HEAD); then + head=$(printf '%s\n' "$advertised" | sed -n 's|^ref: refs/heads/\([^[:space:]]*\)[[:space:]]*HEAD$|\1|p') + [ -n "$head" ] && git -C "$repository" symbolic-ref HEAD "refs/heads/$head" + else + echo "git-mirror: the default branch of $name could not be read" >&2 + status=1 + fi + # git-http-backend serves only repositories with this file. + touch "$repository/git-daemon-export-ok" # cgit shows the age of the last change of a repository from this file. git -C "$repository" for-each-ref --sort=-committerdate --count=1 \ --format='%(committerdate:iso8601)' refs/heads > "$repository/info/web/last-modified" @@ -51,4 +58,17 @@ for name in $names; do status=1 fi done +# A repository no longer listed stops being served at once and is removed. +for repository in "$root"/*.git; do + [ -d "$repository" ] || continue + name=$(basename "$repository" .git) + case " $(printf '%s ' $names)" in + *" $name "*) ;; + *) + rm -f "$repository/git-daemon-export-ok" + rm -rf -- "$repository" + echo "git-mirror: removed $name, which is no longer listed" >&2 + ;; + esac +done exit "$status" diff --git a/ops/git/nginx/git.conf b/ops/git/nginx/git.conf index c11dce4..71c5b75 100644 --- a/ops/git/nginx/git.conf +++ b/ops/git/nginx/git.conf @@ -80,7 +80,7 @@ server { include fastcgi_params; fastcgi_param SCRIPT_FILENAME /usr/libexec/git-core/git-http-backend; fastcgi_param GIT_PROJECT_ROOT /srv/git/mirrors; - fastcgi_param GIT_HTTP_EXPORT_ALL ""; + # No GIT_HTTP_EXPORT_ALL: only mirrors git-mirror marks with git-daemon-export-ok are served. fastcgi_param PATH_INFO /$git_repo.git/$git_path; fastcgi_param REMOTE_USER ""; # The mirrors belong to gitmirror and are read as cgit; only this backend trusts them. |