abhigyanpatwari/GitNexus · critical · SandboxError

target .gitnexus path must be a real directory before graph

Error message

target .gitnexus path must be a real directory before graph preparation

What it means

Precondition guard in _neutralize_target_index_inputs. The clone's '.gitnexus' path, if present, must be a real directory (not a symlink, not a regular file) before the harness removes it and writes neutral control files. A symlinked or file '.gitnexus' is treated as a sandbox-escape attempt (pointing at an external graph) and rejected. An absent '.gitnexus' is fine: the harness simply creates the control files.

Source

Thrown at eval/workflow_bench/sanitized_graph.py:141

        while view:
            written = os.write(descriptor, view)
            if written <= 0:
                raise OSError(f"short write while neutralizing {name}")
            view = view[written:]
        os.fsync(descriptor)
    finally:
        os.close(descriptor)


def _neutralize_target_index_inputs(root: Path) -> None:
    index = root / ".gitnexus"
    try:
        metadata = index.lstat()
    except FileNotFoundError:
        metadata = None
    if metadata is not None:
        if stat.S_ISLNK(metadata.st_mode) or not stat.S_ISDIR(metadata.st_mode):
            raise SandboxError("target .gitnexus path must be a real directory before graph preparation")
        shutil.rmtree(index)
    _replace_control_file(root, ".gitnexusrc", b"{}\n")
    _replace_control_file(root, ".gitnexusignore", b"")


def _scrub_source_references(root: Path) -> tuple[str, ...]:
    """Remove graph inputs whose path or stored content references the harness.

    The disposable graph seed may contain docs or shipped skill copies outside
    the removed harness that name its paths. They are harmless implementation
    context in an arm checkout, but indexing them would let graph/MCP queries
    recover benchmark-specific hints. Scan the exact <=512 KiB file universe
    admitted by the pinned analyzer and remove contaminated inputs before the
    graph is built. Target-controlled ignore/config files are not consulted.
    """

    marker_bytes = tuple(marker.encode() for marker in GRAPH_MARKERS)
    pending: list[tuple[Path, PurePosixPath]] = [(root, PurePosixPath())]

View on GitHub (pinned to d540b00184)

Solutions

  1. Inspect the clone root before neutralization: 'ls -la <clone>/.gitnexus' and confirm it is either absent or a real directory.
  2. Remove any symlink or regular-file '.gitnexus' from the task fixture or sandbox_copy source.
  3. Ensure no sandbox_dependency target is '.gitnexus' and no sandbox_copy entry creates it.
  4. Let the harness build the graph in-sandbox; do not pre-populate .gitnexus by any mechanism.

Example fix

# before (fixture pre-seeds a graph via symlink)
ln -s /prebuilt/graph .gitnexus
# after (let the harness create and index from scratch)
rm .gitnexus
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
import stat

clone = Path("clone-root")
g = clone / ".gitnexus"
if g.is_symlink():
    raise SystemExit(".gitnexus is a symlink; remove it")
try:
    mode = g.lstat().st_mode
except FileNotFoundError:
    pass
else:
    if not stat.S_ISDIR(mode):
        raise SystemExit(".gitnexus must be a real directory or absent")

Type guard

from pathlib import Path
import stat

def gitnexus_is_safe_to_neutralize(clone_root: Path) -> bool:
    g = clone_root / ".gitnexus"
    try:
        mode = g.lstat().st_mode
    except FileNotFoundError:
        return True
    return stat.S_ISDIR(mode) and not stat.S_ISLNK(mode)

Try / catch

try:
    _neutralize_target_index_inputs(clone_root)
except SandboxError as exc:
    if "real directory before graph preparation" in str(exc):
        log.error(".gitnexus is a symlink/file (possible escape attempt); remove it")
    raise

Prevention

When it happens

Trigger: A sanitized clone root contains a '.gitnexus' that lstat reports as a symlink or as a non-directory inode. This typically means a task fixture or sandbox_copy entry planted a '.gitnexus' link/file to smuggle in a prebuilt graph.

Common situations: A task tries to seed a graph by symlinking .gitnexus -> /some/prebuilt; a fixture created .gitnexus as a marker file; a sandbox_copy of a parent directory dragged in a .gitnexus regular file; a previous failed run left a stale file (less likely, since rmtree would have handled a dir).

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/decccb29da8c7fc5. Report an issue: GitHub.