Nimblesite / Nimblesite/Basilisk

Detect first-party / third-party package name collision (declared PyPI dep shadows local package)

Open
#47 1 comment 0 reactions 0 assignees View on GitHub

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 — see crates/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\"], and dependencies = [\"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 → import pydantic_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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.