aboutsummaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-06-24 10:28:04 +0200
committerDanilo M. <danix@danix.xyz>2026-06-24 10:28:04 +0200
commit9c301a8eac944083556b3dce297764b4fca7d49a (patch)
tree5637367f51e28a240da82a27549c2aef5fb2b126 /CLAUDE.md
parent02a5ae2adc2df39fc78fd7e29904ff473e9266a0 (diff)
downloadgitctl-9c301a8eac944083556b3dce297764b4fca7d49a.tar.gz
gitctl-9c301a8eac944083556b3dce297764b4fca7d49a.zip
docs: bring CLAUDE.md, README, TODO current after the three features
- CLAUDE.md: new hard rule that removal functions are exact inverses of their add counterparts (round-trip self-tests); TRASH_DIR added to the server constants; verified-live list extended with list-repos and a full delete cycle. - README: TRASH_DIR in the server-install constants and its dir note. - TODO: items 1-3 already marked done; cross-cutting work folded in; remaining leftovers listed (repo-name completion, the cosmetic No changes. echo, and the YAGNI gc-trash prune verb). - Removed all pre-existing em dashes from CLAUDE.md and README. Docs only, no code change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'CLAUDE.md')
-rw-r--r--CLAUDE.md24
1 files changed, 15 insertions, 9 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
index a56836c..7146290 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -8,9 +8,9 @@ a SlackBuild.
Two single-file scripts, no shared module:
-- `gitctl` — client, runs on the laptop. Dumb caller: loads TOML config, edits
+- `gitctl`: client, runs on the laptop. Dumb caller: loads TOML config, edits
the local gitolite-admin clone and pushes, shells out to the helper over SSH.
-- `gitctl-helper` — server helper, runs as the git user over a `command=`-restricted
+- `gitctl-helper`: server helper, runs as the git user over a `command=`-restricted
SSH key. Holds all parsing-heavy logic. Dispatches on `SSH_ORIGINAL_COMMAND`.
The restricted key forces `gitctl-helper` regardless of the command the client
@@ -19,8 +19,8 @@ fed to argparse. **No shell string interpolation, ever.** The client mirrors thi
with `shlex.quote`; the round-trip is pinned in both self-tests.
Two distinct SSH aliases, enforced different at config load:
-- `push_ssh_alias` (e.g. `git_push`) — normal unrestricted git pushes
-- `helper_ssh_alias` (e.g. `git_helper`) — restricted helper key, also `User git`
+- `push_ssh_alias` (e.g. `git_push`): normal unrestricted git pushes
+- `helper_ssh_alias` (e.g. `git_helper`): restricted helper key, also `User git`
The helper runs as the **git** user, not root (the target server has
`PermitRootLogin no`). git owns the bare repos' `description` files already; for
@@ -29,7 +29,7 @@ git cannot create temp inodes in `/etc`, cgitrc is written **in place** (not via
atomic rename), with a pre-write backup to `BACKUP_DIR`
(`/var/lib/gitolite3/cgitrc-backups`).
-The helper key does NOT go in git's normal `~/.ssh/authorized_keys` — gitolite
+The helper key does NOT go in git's normal `~/.ssh/authorized_keys`; gitolite
owns and regenerates that file, and an existing gitolite key would match first
and run `gitolite-shell` (`FATAL: unknown git/gitolite command`). It lives in a
separate `AuthorizedKeysFile` (`~git/.ssh/gitctl_keys`) wired via a
@@ -47,9 +47,13 @@ separate `AuthorizedKeysFile` (`~git/.ssh/gitctl_keys`) wired via a
- **cgitrc section blocks are flush-left and positional.** `section=` is positional,
so a new repo block must be inserted at the end of the section's span:
before the next `section=` line OR the next banner comment
- (`# ---------- Name ------------#`), whichever comes first — a banner belongs
+ (`# ---------- Name ------------#`), whichever comes first; a banner belongs
to the section it precedes (`insert_repo_block`, `BANNER_RE`). Ending the span
only at `section=` drops the block under the following section's banner.
+- **Removal functions are exact inverses of their add counterparts.**
+ `remove_repo_block` undoes `insert_repo_block`, `remove_stanza` undoes
+ `add_stanza`: insert/add then remove must return the original. This is pinned
+ by round-trip self-tests; keep them passing when touching either side.
- **`description` file is owned `git:gitolite3`** (system user git, group gitolite3,
no gitolite3 user). `set-desc` writes in place (truncate-write) to preserve owner,
with `os.chown` back as insurance.
@@ -71,10 +75,12 @@ rejection paths) then `self-test OK`. Run both after any change.
## Server constants (top of gitctl-helper)
-`REPO_BASE`, `CGITRC`, `SYNC_SCRIPT`, `BACKUP_DIR`, `DEFAULT_OWNER` — must match
-the actual server. Confirmed against the real `/etc/cgitrc` and
+`REPO_BASE`, `CGITRC`, `SYNC_SCRIPT`, `BACKUP_DIR`, `TRASH_DIR`, `DEFAULT_OWNER`
+must match the actual server (`TRASH_DIR` is where `delete` moves bare repos,
+outside `REPO_BASE`). Confirmed against the real `/etc/cgitrc` and
`sync-cgit-descs.py`. Verified end to end on the live server (read, section add,
-two-phase repo create, desc, sync, idempotency, backups).
+two-phase repo create, desc, sync, idempotency, backups, list-repos, and a full
+delete cycle with the bare repo landing in `TRASH_DIR`).
## Docs / design