{"record":{"id":"9ab6a73885670ef8","repo":"abhigyanpatwari/GitNexus","slug":"evidence-must-be-a-regular-non-symlink-file-valu","errorCode":null,"errorMessage":"evidence must be a regular non-symlink file: {value}","messagePattern":"evidence must be a regular non-symlink file: (.+?)","errorType":"exception","errorClass":"SandboxError","httpStatus":null,"severity":"error","filePath":"eval/workflow_bench/proposer_sandbox.py","lineNumber":198,"sourceCode":"\ndef redact_text(text: str, secrets: Sequence[str] = ()) -> str:\n    for secret in secrets:\n        if secret:\n            text = text.replace(secret, \"[REDACTED]\")\n    text = _TOKEN_PATTERNS[0].sub(\"[REDACTED]\", text)\n    text = _TOKEN_PATTERNS[1].sub(\"[REDACTED]\", text)\n    text = _TOKEN_PATTERNS[2].sub(r\"\\1[REDACTED]\", text)\n    return _TOKEN_PATTERNS[3].sub(r\"\\1[REDACTED]@\", text)\n\n\ndef _evidence_bytes(value: Any, secrets: Sequence[str]) -> bytes:\n    if isinstance(value, Path):\n        try:\n            mode = value.lstat().st_mode\n        except OSError as exc:\n            raise SandboxError(f\"evidence path is unreadable: {value}: {exc}\") from exc\n        if value.is_symlink() or not stat.S_ISREG(mode):\n            raise SandboxError(f\"evidence must be a regular non-symlink file: {value}\")\n        if value.stat().st_size > MAX_EVIDENCE_FILE_BYTES:\n            raise SandboxError(f\"evidence exceeds the per-file limit: {value}\")\n        raw = value.read_bytes()\n        return redact_text(raw.decode(errors=\"replace\"), secrets).encode()\n    if isinstance(value, bytes):\n        raw = value\n    elif isinstance(value, str):\n        raw = value.encode()\n    else:\n        raw = (json.dumps(value, sort_keys=True, separators=(\",\", \":\")) + \"\\n\").encode()\n    return redact_text(raw.decode(errors=\"replace\"), secrets).encode()\n\n\ndef stage_evidence_bundle(\n    destination: Path,\n    entries: Mapping[str, Any],\n    *,\n    secrets: Sequence[str] = (),","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/proposer_sandbox.py#L180-L216","documentation":"Raised by _evidence_bytes when a Path evidence value is a symlink or not a regular file (stat.S_ISREG false). The contract forbids symlinks and special files because they could redirect the redaction pass at the real target or yield non-file bytes (FIFO/socket/device), defeating the byte cap and redaction guarantees.","triggerScenarios":"stage_evidence_bundle is handed a Path that lstat's as a symlink, a directory, a named pipe, a unix socket, a block/char device, or any non-regular inode.","commonSituations":"Evidence 'file' is actually a symlink created by a test harness for convenience; a directory was passed where a single file was expected; /tmp evidence path collided with an OS FIFO; a socket file was left in the workspace by a dev server; the proposer wrote evidence through a symlink farm.","solutions":["Replace the symlink with the real file: read the target and pass its bytes, or copy the target into a plain file with shutil.copyfile then stage that.","If you meant to stage a directory, enumerate its regular files and stage each as its own simple-name entry.","Reject special files upstream: assert value.is_file() and not value.is_symlink() before building the entries mapping.","For symlinks you control, dereference explicitly with value.resolve(strict=True) and stage the resolved regular file."],"exampleFix":"// before\nentries = {\"out\": Path(\"/workspace/out\")}  # /workspace/out -> /secret/log\n// after\ntarget = Path(\"/workspace/out\").resolve(strict=True)\nassert target.is_file() and not target.is_symlink()\nentries = {\"out\": target}","handlingStrategy":"validation","validationCode":"import stat\nfrom pathlib import Path\n\ndef is_regular_nonsymlink(p: Path) -> bool:\n    try:\n        mode = p.lstat().st_mode\n    except OSError:\n        return False\n    return stat.S_ISREG(mode) and not stat.S_ISLNK(mode)\n\nassert all(is_regular_nonsymlink(v) for v in entries.values() if isinstance(v, Path))","typeGuard":"import stat\nfrom pathlib import Path\n\ndef is_regular_non_symlink_file(value: object) -> bool:\n    if not isinstance(value, Path):\n        return False\n    try:\n        mode = value.lstat().st_mode\n    except OSError:\n        return False\n    return stat.S_ISREG(mode) and not stat.S_ISLNK(mode)","tryCatchPattern":"try:\n    stage_evidence_bundle(dest, entries, secrets=secrets)\nexcept SandboxError as exc:\n    if 'regular non-symlink' in str(exc):\n        # resolve and replace the offending entry with its real target bytes\n        bad = extract_path_from(exc)\n        entries[bad.name] = bad.resolve(strict=True).read_bytes()\n    raise","preventionTips":["Never stage symlinks; dereference and stage the target bytes.","Add a CI check that rejects symlinks inside evidence directories.","Use shutil.copyfile to materialize plain files before staging.","For directories, enumerate and stage each regular file individually."],"tags":["evidence","filesystem","symlink","sandbox","security"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}