From 2efbcea4785402134c4db09d3febda0e82aab71e Mon Sep 17 00:00:00 2001 From: WebX11 SysOp Date: Thu, 5 Nov 2026 22:26:25 +0100 Subject: feat(git): contrib push surface with automated moderation Users push to push.newos.webx11.duckdns.org with a per-user token; the read-only host is untouched. http.receivepack is unset so git only allows receive-pack when REMOTE_USER is present, which only that vhost sets. A pre-receive hook (installed by the publisher every run) allows refs/heads/contrib/* only and refuses banned paths, credential-shaped blobs, >200 files or >2MB, logging user+ref+decision. moderate-contrib.py triages every 10 min: deletes hard violations, stamps the rest ready-docs/review/stale into a queue rendered at /admin/git-contrib.html. A human still decides what merges. Verified end to end: contrib push accepted, main refused, credential file refused, accepted ref visible on the read-only host; guard extended (push host 401, hook present+executable, receivepack unset) and proven RED by removing the hook. --- docs/usage.html | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'docs/usage.html') diff --git a/docs/usage.html b/docs/usage.html index 4fbb7cb..017f6e4 100644 --- a/docs/usage.html +++ b/docs/usage.html @@ -286,6 +286,42 @@ pi -p --no-session --no-tools --mode json --model gemma4:31b-cloud \

The mirror only fast-forwards, so git pull --ff-only can never wedge. Nothing here can push — the repository refuses receive-pack at three levels.

+

Contributing (contrib branches)

+

The mirror accepts contributions, but only as contrib branches — main is +generated from the platform's monorepo and a push to it would be erased by the next publish. Pushes go to +a separate host that asks for credentials; the read-only host in your origin stays anonymous +and read-only.

+
# 1. one token per account, issued by the platform operator
+#    (looks like: https://<user>:wx11gp_…@push.newos.webx11.duckdns.org/newos4.git)
+git remote add push https://push.newos.webx11.duckdns.org/newos4.git
+
+# 2. work on a branch, push it under contrib/
+git switch -c contrib/my-fix
+git commit -am "fix(shell): handle an empty command"
+git push push HEAD:refs/heads/contrib/my-fix
+

Use a credential helper rather than pasting the token into the +URL of a repository you might publish. Git will ask once and can remember it +(git config --global credential.helper store writes it to a plain file — choose +cache or your OS keychain if that matters).

+ +

What the server enforces

+ + + + + + + +
RuleReason
Only refs/heads/contrib/*main and tags are generated by the publisher; a push there would disappear at the next publish
No credentials in the diffThe repository is public. Every added blob is scanned before it is accepted; a match rejects the whole push with the file name
No profile or key files.user.json, .session, .env, *.pem, id_rsa are refused by path
≤ 200 files, ≤ 2 MB of new content per pushKeeps one push from making the mirror unusable
Deleting your own contrib branchAllowed — it is your branch
+ +

What happens after you push

+

A moderator triages every branch automatically: docs-only changes are marked ready, anything +touching code is queued for a human with a diff summary, and a branch that breaks a hard rule is deleted. +The queue is visible to the operator; you will hear back on your branch, not in a black hole.

+
git fetch push 'refs/heads/contrib/*:refs/remotes/contrib/*'
+git log --oneline main..contrib/my-fix      # what your branch adds
+git push push --delete contrib/my-fix       # withdraw it
+

Updating later

cd newos4
 git pull --ff-only          # the mirror only ever fast-forwards
-- 
cgit v1.2.3