{"record":{"id":"a5d6c0f43387a351","repo":"abhigyanpatwari/GitNexus","slug":"compound-engineering-plugin-manifest-directory-mus","errorCode":null,"errorMessage":"Compound Engineering plugin manifest directory must be real: {manifest_root}","messagePattern":"Compound Engineering plugin manifest directory must be real: (.+?)","errorType":"exception","errorClass":"SandboxError","httpStatus":null,"severity":"error","filePath":"eval/workflow_bench/runtime_mounts.py","lineNumber":298,"sourceCode":"        if lowered.startswith(\".env.\") or lowered.startswith(\".npmrc.\"):\n            return True\n        if lowered.endswith(_SECRET_SUFFIXES) or any(marker in lowered for marker in _SECRET_NAME_MARKERS):\n            return True\n    return False\n\n\ndef _plugin_files(source: Path) -> Iterator[tuple[PurePosixPath, Path]]:\n    \"\"\"Yield only allowlisted plugin files in stable order.\"\"\"\n\n    manifest_root = source / \".claude-plugin\"\n    try:\n        manifest_root_metadata = manifest_root.lstat()\n    except OSError as exc:\n        raise SandboxError(\n            f\"Compound Engineering plugin manifest directory is unavailable: {manifest_root}: {exc}\"\n        ) from exc\n    if stat.S_ISLNK(manifest_root_metadata.st_mode) or not stat.S_ISDIR(manifest_root_metadata.st_mode):\n        raise SandboxError(f\"Compound Engineering plugin manifest directory must be real: {manifest_root}\")\n    required_manifest = _ALLOWED_PLUGIN_MANIFESTS[0]\n    manifest_path = source / Path(*required_manifest.parts)\n    if not manifest_path.exists():\n        raise SandboxError(f\"Compound Engineering plugin manifest is missing: {manifest_path}\")\n    for relative in _ALLOWED_PLUGIN_MANIFESTS:\n        candidate = source / Path(*relative.parts)\n        if candidate.exists():\n            yield relative, candidate\n\n    skills = source / \"skills\"\n    if not skills.exists():\n        raise SandboxError(f\"Compound Engineering plugin skills directory is missing: {skills}\")\n\n    def walk(directory: Path, relative_dir: PurePosixPath) -> Iterator[tuple[PurePosixPath, Path]]:\n        try:\n            with os.scandir(directory) as scanned:\n                entries = sorted(scanned, key=lambda entry: entry.name)\n        except OSError as exc:","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/runtime_mounts.py#L280-L316","documentation":"Even when .claude-plugin/ can be lstat'd, the harness rejects it if the mode is a symlink (stat.S_ISLNK) or not a directory (not stat.S_ISDIR). Real directories are required so a symlink cannot redirect manifest reads outside the bounded source.","triggerScenarios":"source/.claude-plugin is a symlink to another location, a regular file, or any non-directory file type.","commonSituations":"Plugin shipped with a convenience symlink; operator symlinked .claude-plugin from a shared location for testing; tarball extraction preserved a symlink instead of materializing it.","solutions":["Replace the symlink with a real directory: `rm <plugin>/.claude-plugin && mkdir <plugin>/.claude-plugin && cp -r <real>/.claude-plugin/. <plugin>/.claude-plugin/`.","Re-extract the plugin tarball with `tar --no-same-owner -xhf` (the `-h` dereferences symlinks at extraction time)."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import stat\nfrom pathlib import Path\n\ndef manifest_dir_is_real(source: Path) -> bool:\n    p = source / \".claude-plugin\"\n    try:\n        mode = p.lstat().st_mode\n    except OSError:\n        return False\n    return not stat.S_ISLNK(mode) and stat.S_ISDIR(mode)","typeGuard":null,"tryCatchPattern":"try:\n    list(_plugin_files(source))\nexcept SandboxError as exc:\n    if \"manifest directory must be real\" in str(exc):\n        # replace the symlink with a real directory\n        ...\n    raise","preventionTips":["Never symlink the .claude-plugin directory.","Extract plugin tarballs with dereference (`tar -xhf`) to avoid persisting symlinks."],"tags":["symlink-guard","ce-plugin","sandbox","manifest"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}