The direct answer
Treat patch generation as a configured program boundary, not an inert file read. Select trusted complete local objects and configuration, fix the tree pair and arguments, explicitly disable external diff, text conversion and paging, and admit only bounded complete output. These controls do not make arbitrary repositories safe to execute.
Define the comparison before choosing flags
Imagine an assistant explaining a one-sentence change between fictional trees T-A and T-B. A trusted service has already admitted both complete trees and their reachable content into its own local object store. Its manifest records the approved pair, store revision and comparison scope. These are symbolic labels, not real object IDs or observed results.
The supplied material is repository content, not an unpacked Git directory. The Git security guidance warns against running commands in an untrusted Git directory or its surrounding working tree. File ownership alone does not establish configuration trust.
The proposed service owns the store, configuration and includes, attribute sources and process environment. It excludes missing/promisor objects, external object-store dependencies and attacker-writable metadata. Object admission is a separate reviewed workflow; no cloning, importing or repository construction is performed here.
Separate the three helper selection paths
The four official manuals inspected here identify their documentation as Git 2.56.0. No installed Git version was inspected. The attributes manual explains that a path can select a diff driver whose command is defined in configuration. Textconv instead runs a conversion program before Git computes a textual comparison; that view can lose information and is not directly applicable as a patch.
The configuration manual documents diff.external, its GIT_EXTERNAL_DIFF override, and a pager command interpreted by a shell. Pager preference starts with GIT_PAGER, then core.pager, then PAGER. Includes and runtime configuration variables also affect the effective settings.
An argument array with shell execution disabled at the outer launcher does not settle what Git itself may select. This worker requires an allowlisted environment and reviewed configuration across every active scope. It cannot inherit arbitrary caller-supplied Git variables or assume changing one local key neutralizes other sources.
Freeze one documented argument profile
This proposed layout was not run. STORE is the trusted service-selected Git directory; TREE_A and TREE_B represent full independently approved tree object identities. No caller supplies revision expressions, paths, URLs or extra options.
git --git-dir=STORE --no-pager --no-replace-objects --no-lazy-fetch --attr-source=TREE_B
diff --no-ext-diff --no-textconv --no-renames --ignore-submodules=all
--no-color --no-relative --exit-code TREE_A TREE_B --The diff manual permits two-tree comparison. External-driver and text-conversion switches address separate paths. Rename detection is disabled; the selected submodule setting hides those changes. Relative-path filtering is countermanded, with no pathspecs after the terminator.
The global options select the repository without discovery, disable paging and replacement refs, prevent on-demand fetching from a promisor remote, and select the attribute tree. That tree selection does not erase info/global/system attribute inputs; their trust remains a prerequisite. These scopes are not a general network or subprocess prohibition.
Admission separately requires no submodule entries and reviewable ordinary text changes. Without rename pairing, a rename can appear as deletion and addition. Binary summaries or excluded content cannot support a claim that all changed content was reviewed.
Require a complete result within the declared scope
With --exit-code, the diff manual distinguishes zero for no differences and one for differences. A difference is not automatically an operational failure. Neither status alone proves a complete captured result.
The proposed supervisor retains the input pair and profile, captures bounded output, waits for process completion and complete stream collection, and distinguishes that completion from timeout, signal, truncation or another error. Every limit failure denies handoff as a complete comparison, even when its prefix looks useful. Empty captured output is not evidence of identical trees.
Keep the child without application credentials and constrain network, filesystem access, CPU, memory, wall time and output independently. Missing objects stop the comparison; no repair fetch, credential prompt or relaxed rerun is authorized. These are application requirements, not properties established by the switches. Git bugs, resource costs, temporary activity and all possible subprocesses are not ruled out.
Eight inert comparison admission cards
All cards are PROPOSED_UNRUN. Record store/config revision, fixed tree pair, helper category, controls, completion/coverage label and handoff decision. No candidate repository, attributes, configuration, helper, patch or process was created or inspected.
| Card | Invented condition | Proposed decision |
|---|---|---|
| 1. Ordinary note change | Trusted complete store; T-A/T-B; one sentence differs; full bounded completion labeled successful. | Admit the complete selected text representation as untrusted review context; authorize no action from it. |
| 2. External diff selection | A driver/configuration category would choose a command. | Require the explicit no-external-driver profile and trusted effective configuration. An unexpected helper attempt fails admission. |
| 3. Text conversion selection | A blob requests a conversion view. | Keep textconv disabled. If ordinary content is unavailable, mark the comparison insufficient for that review. |
| 4. Pager selection | An inherited pager category differs from the reviewed environment. | Deny that environment; retain the global no-pager option. A pipe alone is not the declared control. |
| 5. Additional producer arguments | The caller requests another revision expression, path restriction or option. | Reject before invocation; require a separately approved scope rather than extending this vector. |
| 6. Missing or external objects | The store cannot satisfy its complete-local-object promise. | Stop with incomplete-input status; do not fetch, prompt for credentials or infer a complete patch. |
| 7. Hidden or opaque changes | Submodules, binary summaries or excluded content appear in admission evidence. | Reject the claimed whole-change review; route that workload to a separate explicit profile. |
| 8. Prefix without completion | Output cap, timeout, process error or incomplete stream collection occurs. | Deny complete-comparison eligibility; preserve a bounded failure reason, not an apparent successful patch. |
Keep patch text outside the authority boundary
A completed comparison remains untrusted model input. It does not authenticate an author, prove code safety, approve instructions in comments, or authorize applying, running, committing or deploying the change. Preserve the tree pair and coverage limits alongside the request.
Documentation was fetched, but no candidate Git command, helper, pager, configuration inspection, object operation, fixture or model call was performed. Ordinary trusted repository maintenance is separate evidence. Boundary is prelaunch; its planned request checks and separate synthetic action demo do not implement this Git review service.
Primary sources
Official references supporting the guidance. Examples in this guide are synthetic and are not reports of a production incident.