{"record":{"id":"55e99d95b3aceeee","repo":"abhigyanpatwari/GitNexus","slug":"oracle-sanitization-left-unreachable-git-objects-r","errorCode":null,"errorMessage":"oracle sanitization left unreachable Git objects recoverable","messagePattern":"oracle sanitization left unreachable Git objects recoverable","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"critical","filePath":"eval/workflow_bench/oracle_assets.py","lineNumber":424,"sourceCode":"        logs_metadata = logs.lstat()\n        if stat.S_ISLNK(logs_metadata.st_mode) or not stat.S_ISDIR(logs_metadata.st_mode):\n            raise ValueError(\"unsafe Git reflog metadata blocks oracle sanitization\")\n        shutil.rmtree(logs)\n\n    _git_checked(root, [\"repack\", \"-A\", \"-d\"], timeout=600)\n    _git_checked(root, [\"prune\", \"--expire=now\"], timeout=600)\n    _git_checked(root, [\"prune-packed\"], timeout=600)\n\n    remaining_refs = _git_checked(root, [\"for-each-ref\", \"--format=%(refname)\"], timeout=60)\n    if remaining_refs:\n        raise ValueError(\"oracle sanitization left clone references recoverable\")\n    fsck = run_checked(\n        [\"git\", \"-C\", str(root), \"fsck\", \"--full\", \"--no-progress\", \"--no-reflogs\", \"--unreachable\"],\n        timeout=600,\n        tail_bytes=MAX_CLONE_REF_BYTES,\n    )\n    if fsck.stdout_tail.strip() or fsck.stderr_tail.strip():\n        raise ValueError(\"oracle sanitization left unreachable Git objects recoverable\")\n\n    forbidden_objects: list[tuple[str, str]] = []\n    if original_head != sanitized_head:\n        forbidden_objects.append((original_head, \"original commit\"))\n    if hidden_tree:\n        forbidden_objects.append((hidden_tree, \"hidden harness tree\"))\n    for forbidden_object, label in forbidden_objects:\n        probe = run_managed(\n            [\"git\", \"-C\", str(root), \"cat-file\", \"-e\", forbidden_object],\n            timeout=60,\n        )\n        if probe.ok:\n            raise ValueError(f\"oracle sanitization left the {label} recoverable\")\n        if probe.state != \"exited\" or probe.returncode not in {1, 128}:\n            raise ValueError(f\"oracle sanitization could not verify removal of the {label}\")\n\n    hidden_listing = _git_checked(\n        root,","sourceCodeStart":406,"sourceCodeEnd":442,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/oracle_assets.py#L406-L442","documentation":"Post-condition: after repack + prune, `git fsck --full --no-reflogs --unreachable` must produce no output. Any stdout/stderr means unreachable objects (including the original commit or harness tree) are still present and could be read via `git cat-file`, so the harness treats the clone as leaking oracle data.","triggerScenarios":"Triggered when git prune/repack did not actually remove unreachable objects — commonly because gc.pruneExpire or gc.reflogExpireUnreachable kept them, a leftover .keep file pinned a pack, or prune ran with a grace period.","commonSituations":"Repo config with gc.pruneExpire=2weeks; a .keep file on the pack holding the original commit; running on a git with default gc that respects a recent-object grace; reflog entries that were not expired before prune.","solutions":["Force expiry and prune: `git -C <clone> -c gc.reflogExpire=now -c gc.reflogExpireUnreachable=now reflog expire --all && git -C <clone> gc --prune=now`.","Remove .keep files: `rm -f <clone>/.git/objects/pack/*.keep`, then `git -C <clone> repack -ad && git -C <clone> prune --expire=now`.","Check config: `git -C <clone> config --get gc.pruneExpire` and override to 'now' for the benchmark.","Re-clone and sanitize in a clean environment."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"from pathlib import Path\nfrom eval.workflow_bench.process_control import run_managed\n\ndef no_unreachable_objects(clone: Path) -> bool:\n    r = run_managed([\"git\", \"-C\", str(clone), \"fsck\", \"--full\", \"--no-progress\", \"--no-reflogs\", \"--unreachable\"], timeout=600)\n    return not (r.stdout_tail.strip() or r.stderr_tail.strip())\n","typeGuard":"def is_unreachable_recoverable(exc: BaseException) -> bool:\n    return isinstance(exc, ValueError) and \"unreachable Git objects recoverable\" in str(exc)\n","tryCatchPattern":"try:\n    oracle_assets.sanitize_clone_for_hidden_oracles(clone)\nexcept ValueError as exc:\n    # Unreachable oracle-bearing objects may still be cat-file-able; abort.\n    quarantine(clone)\n    raise AbortTask(str(exc)) from exc\n","preventionTips":["Set gc.pruneExpire=now and gc.reflogExpireUnreachable=now in the clone config before sanitizing.","Do not place .keep files on benchmark-clone packs.","Treat this as a potential oracle leak, not a recoverable error."],"tags":["git","fsck","prune","gc","data-leak","oracle","sanitization","postcondition","invariant"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}