nisse-review: read code from a git clone kept between runs #160

Merged
dev-agent merged 1 commits from review-clone into main 2026-10-17 22:12:52 +00:00
Collaborator

Stacked on #159 (it uses #159's stop flag and Stopped); I'll retarget it to main once #159 merges.

Why: archives were downloaded and unpacked afresh for every run that read code; that doesn't scale to very large repositories.

What

  • nisse_review.clones: each repository is cloned once, full history, under scratch/repos/<owner>/<name>/. head/ is the clone, checked out at the PR's head. base/ is a git worktree, made only when the model reads ref: base.
  • Each run fetches every branch plus refs/pull/N/head (which also covers PRs from forks), then checkout --force --detach <head> and clean -ffdx, so nothing from an earlier PR is left. If the planned head is gone (force-pushed since), the run fails and the next round picks up the new head.
  • Only the most recently used repository is kept (keep=1); the layout holds several.
  • reader.Repository reads plain folders as before, through a small Trees interface; .git is never listed, searched or read. GiteaClient.archive and the tar unpacking are removed.
  • review.clone / review.fetch log seconds and size.

Git walled off from the code it fetches

  • None of the host's git configuration (GIT_CONFIG_GLOBAL=/dev/null, GIT_CONFIG_NOSYSTEM, own HOME, GIT_CEILING_DIRECTORIES).
  • core.symlinks=false (links arrive as plain files), core.hooksPath=/dev/null, no submodules, GIT_LFS_SKIP_SMUDGE, GIT_ALLOW_PROTOCOL = the configured Gitea URL's scheme only.
  • The token is an http.<gitea url>/.extraHeader in git's environment (GIT_CONFIG_*): never on a command line, in .git/config, or in a URL.
  • A stop ends a running git command (SIGTERM, so git cleans its locks) and raises Stopped; a first clone cut short is deleted.

Tests: test_clones.py against local bare repositories: first clone, a later fetch leaving nothing of the last PR, a second repository replacing the first, the base worktree following its branch, a link arriving as a plain file, a vanished head failing, the token never in arguments or on disk, a stop ending a hanging fetch, and .git hidden from the reader. Each safety rule was mutation-checked (removing it fails a test). Plus a scheduler test: code git can't give fails the run.

Checked by hand against Gitea over HTTPS: clone of dev/nisse in 0.3 s (1.3 MB), the next run a 0.1 s fetch, no file containing the token.

Docs: Architecture R3, Development Plan (M7.5 follow-ups, M7.6 needs git and a persistent scratch/), nisse-review README.

Left out: size limits and a cache cap, keeping several repositories, diffs from local git, running tests in the checkout.

🤖 Generated with Claude Code

https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk

Stacked on #159 (it uses #159's stop flag and `Stopped`); I'll retarget it to `main` once #159 merges. **Why:** archives were downloaded and unpacked afresh for every run that read code; that doesn't scale to very large repositories. **What** - `nisse_review.clones`: each repository is cloned once, full history, under `scratch/repos/<owner>/<name>/`. `head/` is the clone, checked out at the PR's head. `base/` is a git worktree, made only when the model reads `ref: base`. - Each run fetches every branch plus `refs/pull/N/head` (which also covers PRs from forks), then `checkout --force --detach <head>` and `clean -ffdx`, so nothing from an earlier PR is left. If the planned head is gone (force-pushed since), the run fails and the next round picks up the new head. - Only the most recently used repository is kept (`keep=1`); the layout holds several. - `reader.Repository` reads plain folders as before, through a small `Trees` interface; `.git` is never listed, searched or read. `GiteaClient.archive` and the tar unpacking are removed. - `review.clone` / `review.fetch` log seconds and size. **Git walled off from the code it fetches** - None of the host's git configuration (`GIT_CONFIG_GLOBAL=/dev/null`, `GIT_CONFIG_NOSYSTEM`, own `HOME`, `GIT_CEILING_DIRECTORIES`). - `core.symlinks=false` (links arrive as plain files), `core.hooksPath=/dev/null`, no submodules, `GIT_LFS_SKIP_SMUDGE`, `GIT_ALLOW_PROTOCOL` = the configured Gitea URL's scheme only. - The token is an `http.<gitea url>/.extraHeader` in git's environment (`GIT_CONFIG_*`): never on a command line, in `.git/config`, or in a URL. - A stop ends a running git command (SIGTERM, so git cleans its locks) and raises `Stopped`; a first clone cut short is deleted. **Tests:** `test_clones.py` against local bare repositories: first clone, a later fetch leaving nothing of the last PR, a second repository replacing the first, the base worktree following its branch, a link arriving as a plain file, a vanished head failing, the token never in arguments or on disk, a stop ending a hanging fetch, and `.git` hidden from the reader. Each safety rule was mutation-checked (removing it fails a test). Plus a scheduler test: code git can't give fails the run. Checked by hand against Gitea over HTTPS: clone of `dev/nisse` in 0.3 s (1.3 MB), the next run a 0.1 s fetch, no file containing the token. **Docs:** Architecture R3, Development Plan (M7.5 follow-ups, M7.6 needs `git` and a persistent `scratch/`), nisse-review README. Left out: size limits and a cache cap, keeping several repositories, diffs from local git, running tests in the checkout. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
dongar approved these changes 2026-10-17 22:12:07 +00:00
dev-agent changed target branch from review-stop to main 2026-10-17 22:12:33 +00:00
dev-agent added 1 commit 2026-10-17 22:12:33 +00:00
nisse-review: read code from a git clone kept between runs
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 2m3s
CI / e2e (pull_request) Successful in 4m5s
3813ad55d6
Archives were downloaded and unpacked afresh for every run, which doesn't
scale to very large repositories. Each repository is now cloned once, with
its whole history, under scratch/repos/<owner>/<name>/ (head/ the clone,
base/ a worktree when read). A run fetches every branch and the PR's
refs/pull/N/head, checks out the head exactly, and fails if that head is
gone. Only the latest repository is kept for now.

Git runs walled off: none of the host's git configuration, links checked
out as plain files, no hooks, submodules or LFS, only the Gitea URL's
protocol, and the token as an http.extraHeader for that URL in git's
environment only. A stop ends a git command; a cut-short first clone is
removed. The reader never shows .git. GiteaClient.archive is gone.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
dev-agent merged commit fa8d93cf41 into main 2026-10-17 22:12:52 +00:00
dev-agent deleted branch review-clone 2026-10-17 22:12:52 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dev/nisse#160