gitea-saas-core#30: isolated synthetic-merge review workspace #37
No reviewers
Labels
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: pbwraith/gitea-saas-core#37
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "issue-30"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #30 — the review gate now evaluates the exact synthetic merge result in an isolated workspace.
What changed
New:
gitea_saas/review_workspace.py—ReviewWorkspace(clone_dir, runner)builds a clean, isolated, temporary Git worktree per review:originand creates the worktree detached at the base;git merge --no-ffof the exact head onto the exact base inside that worktree (the synthetic merge result; HEAD = the merge commit);conflicted_files, status summary,merge_ok=False) and the test suite is NEVER run against any fallback checkout;gitea_saas/reviewer.py—review_pr(..., workspace=...):git diff --check <base> HEAD(explicit base/result range, acceptance 5) run with cwd = the isolated workspace (acceptance 2/3);workspace).gitea_saas/review_policy.py— before applying any verdict the PR is re-read and the verdict is refused when EITHER the head or the base moved after evaluation (outcome="stale",PAIR_MOVED, zero side effects — acceptance 6); the new pair is eligible for a fresh review. The policy builds the workspace from the newREVIEW_CLONE_DIRconfig knob.gitea_saas/gitea_client.py— the normalized PR shape now carriesbase_sha(alongsidehead_sha).gitea_saas/config.py—REVIEW_CLONE_DIR(README: the READ-ONLY repository clone used to build the isolated review workspace).Hermetic tests (acceptance 8 — local temp git repos, zero network)
tests/test_review_workspace.py(new): clean synthetic merge (both sides' files present, HEAD is a real merge commit, evidence pinned); deterministic merge conflict; the configured clone AND a worker-style issue worktree are never mutated (dirty state survives); cleanup on raised exception, conflict exit, unfetchable SHA, and non-hex inputs; all git commands run in the right cwd (merge inside the workspace, fetch/worktree ops against the clone); explicit-range diff --check from the workspace dir.tests/test_reviewer.py: FakeWorkspace seam; merge conflict -> BOUNCE with evidence and NO test run; no workspace -> NEEDS_GUIDANCE; comment pins head+base; hygiene command is the explicitgit diff --check <base> HEAD; verdict/comment shape untouched.tests/test_review_policy.py: evaluated head move and evaluated base move each refuse the verdict with zero side effects and the new pair gets a fresh chance; workspace passed through when a clone is configured; all fakes mirror the production shape (head_sha + base_sha).Gates
python -m pytest -q— 218 passed, 1 skipped (pre-existing skip in test_intake_eval, unrelated).git diff --check— clean.Out of scope honored: no auth/dashboard PRs, no credential/hosted-service changes, no live Gitea mutation tests, no Stripe changes, no evidence/LLM prompt redesign.
[worker-implemented] gitea-saas-core#30 — commit
d8faabfon branchissue-30(basemain), PR #37.Evidence:
python -m pytest -q— 218 passed, 1 skipped (pre-existing test_intake_eval skip, unrelated).git diff --check— clean.outcome=stale,PAIR_MOVED) with zero side effects; the new pair is fresh-eligible.Acceptance cross-check: 1 (verdict pins repo/pr/head/base) ✓ · 2 (isolated temp worktree from the configured clone; shared main/worker worktrees untouched) ✓ · 3 (fetches named base+head, synthetic merge of exact head onto current base) ✓ · 4 (conflict -> deterministic BOUNCE with evidence, no fallback test run) ✓ · 5 (tests + git diff --check against the merge result with explicit base/result range) ✓ · 6 (policy re-reads the PR; refuses when head or base moved; new pair reviewed fresh) ✓ · 7 (cleanup on success, test failure, conflict, timeout, exceptions) ✓ · 8 (hermetic local-repo tests proving all of the above) ✓ · 9 (pytest + git diff --check green) ✓
[review-gate] VERDICT: BOUNCE
Reviewed exact pair: head
d8faabf2e53fac2657b4f997d10247cec141d1f8onto baseb4e577b31b6b4c7cbdf6a9ac5508bfba64431b02as a clean synthetic merge.Evidence:
python -m pytest -q: 233 passed, 1 skippedgit diff --check b4e577b31b6b4c7cbdf6a9ac5508bfba64431b02 HEAD: cleanBlocking finding:
ReviewWorkspaceinterpolatestmpdirdirectly into commands executed byRunner(shell=True):git worktree add --detach {tmpdir} {base_sha}git worktree remove --force {tmpdir}A valid OS temp path containing spaces or shell metacharacters is therefore split/interpreted by the shell. Construction fails for paths with spaces; more importantly, cleanup can remove the directory with
shutil.rmtreewhile failing to remove Git's worktree administration record. That violates acceptance criterion 7: clean up all temporary paths/worktree state on success, conflict, timeout, and exceptions. This is also relevant to Windows deployments, where space-containing paths are routine.Required repair on the same branch:
shlex.quote(str(path))), including add and remove commands. Keep the already-strict SHA validation.mkdtempprefix filesystem-safe whenrepocontains separators or punctuation.git worktree list --porcelainafter exit.git diff --checkagainst the current base.The synthetic-merge design and pair-movement guard otherwise look sound. Please repair this PR on its existing head branch; do not open a replacement PR.
The review gate builds the synthetic merge in a temporary worktree whose path was interpolated raw into Runner(shell=True) commands: paths with spaces or shell metacharacters were split by the shell, so git's worktree admin entry could survive cleanup (criterion 7 violation; CWD was also misleading on failure). - shlex.quote the worktree path in 'git worktree add --detach' and 'git worktree remove --force'; SHA validation is unchanged. - sanitize the mkdtemp prefix token ('owner/name' -> 'owner-name'), so a repo name with separators/punctuation cannot make mkdtemp fail. - hermetic real-git tests: temp root containing a space and '$' constructs and cleans up completely (dir gone + absent from 'git worktree list --porcelain'); repo token with separators builds a single-component prefix and cleans up.[worker-bounce-fix attempt 1] gitea-saas-core#37 — head
069a74a9(branchissue-30) repairs the review-gate BOUNCE verdict of 2026-08-29.Finding-by-finding:
git worktree add --detach {tmpdir} {base_sha}andgit worktree remove --force {tmpdir}now interpolateshlex.quote(str(tmpdir))for both add and remove (commands go through the sameRunner(shell=True)seam). The already-strict 40-hex SHA validation is unchanged; only path tokens are quoted.repotoken embedded in the prefix is collapsed through_fs_safe_token([^A-Za-z0-9_-]+->-, trimmed), soowner/nameyieldsreview-ws-owner-name-<n>-*; separators/punctuation can no longer turn the prefix into a nested path that makestempfile.mkdtempfail.test_weird_temp_root_with_spaces_and_shell_char_success_and_cleanup— temp rootreview root $weird(space + shell-sensitive$): construction succeeds (merge_ok=True), and after exit the directory is gone AND the clone'sgit worktree list --porcelaincontains noreview-wsentry (no dangling worktree admin record).test_repo_token_with_separators_is_filesystem_safe— repopbwraith/gitea-saas-corebuilds a single-component temp prefix and cleans up completely.069a74a95ce6989fe6a4eb35555d79d7a5c2a2ffonto baseb4e577b31b6b4c7cbdf6a9ac5508bfba64431b02as a clean synthetic merge:python -m pytest -q— 235 passed, 1 skipped (pre-existing intake skip).git diff --check b4e577b31b6b4c7cbdf6a9ac5508bfba64431b02 HEAD— clean.tests/test_review_workspace.py— 11 passed inside the merged tree.The synthetic-merge design and pair-movement guard are unchanged. PR #37 re-verified after push:
state=open,merged=false, headissue-30@069a74a, 9 changed files. Left open for manual review.[review-gate] VERDICT: MERGE
Reviewed exact synthetic merge: head
069a74a95ce6989fe6a4eb35555d79d7a5c2a2ffonto baseb4e577b31b6b4c7cbdf6a9ac5508bfba64431b02.Final evidence:
python3 -m pytest -q: 235 passed, 1 skippedgit diff --check b4e577b31b6b4c7cbdf6a9ac5508bfba64431b02 HEAD: clean$.git worktree list --porcelaincontains no stale review entry.All issue #30 acceptance criteria are satisfied on the current merge result. Merging and closing the linked issue.