Skip to content

Directory names are interpolated unescaped into gitignore patterns, silently indexing 0 files #1806

Description

@MikeBengtson

Summary

GitignoreParser rescopes patterns from nested .gitignore files by prefixing the containing directory's relative path, but does not escape glob metacharacters in that path. A directory whose name contains * therefore produces a pattern that matches far more than it should — in the worst case silently excluding the entire project, so indexing reports 0 files with exit code 0 and no error.

Root cause

serena/util/file_system.py, _parse_gitignore_content (v1.6.1, line 272):

adjusted_pattern = os.path.join(rel_dir, "**", line)

rel_dir is a filesystem name, but it is being interpolated into a pattern context. Lines 263 and 269 have the same issue.

Concrete case

A stray uv/venv directory named *** at the project root. Every venv ships a .gitignore whose entire content is *, so:

  • rel_dir = ***, line = *
  • adjusted pattern = ***/**/*

In gitignore/pathspec syntax *** is just asterisks — a wildcard matching any first segment. So ***/**/* means "ignore every path at depth >= 2." All sources under src/, packages/, etc. are excluded. Root-level files like pyproject.toml survive, which is why nothing errors.

Observed: Indexing: 0it [00:00, ?it/s] / Indexed files per language: (empty), exit 0. With language auto-detection it instead reports No source files for supported language servers were found, which points the user at language configuration — the wrong place entirely.

Verified by running GitignoreParser directly against the project: it loads a spec from ***/.gitignore with adjusted pattern ***/**/*, and should_ignore() returns True for 1009 of 1009 tracked .py files.

Reproduction

mkdir -p repro/pkg && cd repro && git init -q
printf 'def f():\n    pass\n' > pkg/mod.py
mkdir '***' && printf '*\n' > '***/.gitignore'    # what any venv looks like
uvx --from serena-agent serena project index --language python .
# => Indexed files per language:   (empty)   — expected: python=1

Removing the *** directory, or setting ignore_all_files_in_gitignore: false, indexes normally.

Impact

Silent and misdiagnosing. Serena appears configured and healthy, project.yml looks correct, exit code is 0 — but every symbol tool (find_symbol, find_referencing_symbols) returns nothing because the index is empty. In our case this went unnoticed for some time and read as a language-server problem. Any directory named with glob metacharacters triggers it; stray venvs named with asterisks are the realistic path, but foo[1], a{b} and similar would also misbehave.

Suggested fix

Escape glob metacharacters in rel_dir before joining, so the directory name is matched literally. pathspec honors backslash-escaped metacharacters — \*\*\*/ matches only the literal *** directory (confirmed as a workaround). Something equivalent to escaping *?[]{} in rel_dir at all three join sites.

A cheaper mitigation, worth having regardless: warn when a loaded gitignore spec excludes 100% of candidate files, rather than reporting an empty index as success.

Workaround

ignore_all_files_in_gitignore: false plus an explicit ignored_paths list. Note that ls_workspace_folders does not bypass it — the rescoped pattern is matched against project-root-relative paths.

Environment

serena-agent 1.6.1, installed via uvx, macOS (arm64), Python 3.12, LSP backend.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions