mpfaffenberger / mpfaffenberger/code_puppy
Plugin loader: user/builtin name collisions load both copies; user tier lacks namespace isolation (can shadow stdlib via sys.path); __init__.py fallback breaks relative imports
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 814
- Forks
- 278
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 76
Description
File: code_puppy/plugins/__init__.py
Severity: Low-Medium (plugin-loading correctness)
Several correctness gaps in the three-tier plugin loader:
-
User plugins can shadow builtins silently. A user plugin named e.g.
shell_safetyorfile_permission_handlerloads in addition to the builtin of the same name (builtins import viacode_puppy.plugins.<name>.register_callbacks, user plugins via<name>.register_callbacks), so both register callbacks - duplicate prompts/handlers. Project-vs-builtin collisions get a warning (_load_project_plugins, "shadows builtin plugin"), and project-vs-user collisions skip the user copy, but builtin-vs-user collisions are neither deduped nor warned. Suggested: passbuiltin_namesto_load_user_pluginsand at least warn (or skip, matching the documented "only one copy registers" policy). -
User-plugin module names can collide with arbitrary top-level packages.
module_name = f"{plugin_name}.register_callbacks"andsys.modules[module_name] = modulemeans a user plugin directory namedjson,email, etc. registersjson.register_callbacksin sys.modules and - worse -sys.path.insert(0, user_plugins_dir)makes~/.code_puppy/plugins/json/__init__.pyimportable asjson, shadowing the stdlib for the whole process. The project tier already solved this with theproject_plugins.namespace; user plugins should use auser_plugins.namespace the same way (the asymmetry between tiers is itself a there-should-be-one-way violation). -
_load_user_plugins's__init__.pyfallback doesn't set__path__, so a user plugin loaded via__init__.pycannot import its own submodules (from . import x-> ModuleNotFoundError), while the project tier's_ensure_plugin_packagehandles this correctly. Same fix: setsubmodule_search_locations. -
load_plugin_callbacks()returns empty lists on second call instead of the cached result, whileget_loaded_plugins()returns the real data - surprising API; returndict(_loaded_plugin_names)on repeat calls instead.
Filed by Zen Reviewer B (code-puppy-60635a)
Contributor guide
No contributing guide indexed for this repository
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 in code_puppy/plugins/init.py, reading load_plugin_callbacks(), _load_user_plugins(), and the project-tier _ensure_plugin_package for comparison. Trace the three plugin-loading paths and verify the done state: builtin/user collisions are handled consistently, user plugins use namespace isolation without stdlib shadowing, package plugins can import submodules, and repeated loads return cached names.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100