Nimblesite / Nimblesite/Basilisk
Detect first-party / third-party package name collision (declared PyPI dep shadows local package)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 54
- Forks
- 3
- PR merge metrics
- No merged PRs in 30d
Description
Summary
Basilisk should detect when a project declares a PyPI dependency whose distribution/import name collides with a first-party package shipped by the same project, and emit a diagnostic. This class of bug silently pulls an unrelated third-party package into the dependency graph (dependency confusion) and is invisible until something breaks at runtime — or never breaks but ships a supply-chain risk.
Real-world case that prompted this
NimblesiteAgenticPlatform/pyproject.toml:
[project]
name = "nimblesite-agentic-platform"
dependencies = [
...
"nap>=2.0.0", # ← pulls https://pypi.org/project/nap/ ("Convenient way to request HTTP APIs" by Kimmo Brunfeldt)
]
[tool.hatch.build.targets.wheel]
packages = ["src/nap"] # ← the project's OWN code is also called `nap`
The project's import nap.* statements resolve against src/nap/ at dev time. But uv add-style tooling sees the bare nap name in dependencies and dutifully installs a completely unrelated PyPI package called nap. Production installs get both — with undefined precedence depending on installation order, editable-install flags, and sys.path ordering.
Almost certainly added by an LLM/agent that saw import nap.foo somewhere and "helpfully" added a PyPI dep to satisfy it, not realizing the import was first-party.
Why Basilisk is the right place to catch this
Basilisk already knows:
- Local package roots (it has to, for import resolution — see
crates/basilisk-lsp/src/import_resolver.rs). - Declared dependencies (it reads
pyproject.toml— seecrates/basilisk-config/). - Installed site-packages contents (for
BSK-W0010/ py.typed checks).
The check is a 3-way join: "if name appears in both the project's first-party package list and the declared dependency list, that's a collision."
Proposed rule
Code: BSK-W00XX (next available warning code in the dep-hygiene range).
Message: "Declared dependency <name> collides with first-party package <src/path>. The PyPI package will shadow or be shadowed by your own code depending on install order. Either rename the local package or remove the dependency."
Help: Link to the actual PyPI page so the user can immediately see they're pulling an unrelated package (e.g. "PyPI nap is 'Convenient way to request HTTP APIs' by Kimmo Brunfeldt — unrelated to your src/nap/").
Severity: Warning by default. Easy to elevate to error per-project via the suppression / severity config.
Acceptance
- New rule fires on a fixture project where
[project].name = \"foo\",packages = [\"src/foo\"], anddependencies = [\"foo>=1.0\"]. - Does NOT fire when the package is purely first-party (no PyPI dep declared).
- Does NOT fire when there is a PyPI dep but no first-party package of the same name.
- Handles common PyPI naming variants (hyphen vs underscore: PyPI
pydantic-ai→ importpydantic_ai). - Quick-fix offers to either (a) remove the dep line from
pyproject.toml, or (b) rename the local package — at minimum surface a clear command.
Related
This is a class of bug we keep finding because Basilisk doesn't catch dependency-hygiene issues that a competent static analyzer should. See also #43 (E0149 false positives), #46 (W0010 + nonexistent stubs suggestions). The common thread: Basilisk needs more confidence in its diagnostics on the boundary between project code and installed packages — both to avoid false positives (W0010) and to catch real bugs hiding in plain sight (this issue).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing local package discovery in crates/basilisk-lsp/src/import_resolver.rs and dependency parsing in crates/basilisk-config/. Use the fixture described in the acceptance criteria to verify collisions, naming variants, and non-collision cases. Done means the diagnostic, severity configuration, PyPI help, and a clear removal-or-rename quick-fix are covered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, rust
- Domain
- devtools, security
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100