Summary
_descriptor_from_entry_point() raises a bare, uncaught ValueError when a single entry point declares more than one base-cli-api-vN extra. That exception is not a subclass of ExtensionDiscoveryError, and it is raised from _metadata_descriptors() — which every listing/loading entry point (list(), list_commands(), list_profiles(), list_plugins(), load(), load_all()) calls unconditionally before any per-descriptor error isolation kicks in.
Details
lib/python/base_cli/extensions.py:339-357:
def _descriptor_from_entry_point(entry_point: Any) -> ExtensionDescriptor:
...
if len(api_versions) > 1:
raise ValueError("an extension entry point may declare only one base-cli-api-vN extra")
This is called unconditionally from _metadata_descriptors() (extensions.py:273-284), which backs list() (:189-203) and therefore list_commands()/list_profiles()/list_plugins()/load()/load_all() alike. Reproduced directly: registering one fake entry point with extras = ("base-cli-api-v1", "base-cli-api-v2") in a single group makes ExtensionDiscovery.list_commands() raise ValueError uncaught, even though the caller only asked about one group and no other entry point is involved.
This directly contradicts the module's own isolation design: load() (:238-241) wraps its per-descriptor load in except BaseException and re-raises as ExtensionLoadError, and load_all() (:252-261) individually catches ExtensionLoadError/ExtensionCollisionError/ExtensionCompatibilityError per descriptor so one bad extension can't take down the others — but none of that isolation exists for this particular validation error, and it fires even earlier, during metadata-only listing before any extension code is loaded or executed.
Impact
One badly-packaged third-party plugin (a plausible packaging typo — declaring both an old and new base-cli-api-v* extra rather than malicious intent) crashes command/profile/plugin discovery for a host application that never touched that plugin's code, likely at CLI startup. A consumer defensively catching except ExtensionDiscoveryError around discovery calls won't catch this either, since the raised type isn't in that hierarchy.
Suggested fix
Either validate/skip malformed entry points per-descriptor inside _metadata_descriptors() (matching the isolation load_all() already provides), or raise an ExtensionDiscoveryError subclass instead of a bare ValueError so it's at least catchable by the documented exception hierarchy, and have list() skip and continue past the offending descriptor rather than aborting the whole call.
Summary
_descriptor_from_entry_point()raises a bare, uncaughtValueErrorwhen a single entry point declares more than onebase-cli-api-vNextra. That exception is not a subclass ofExtensionDiscoveryError, and it is raised from_metadata_descriptors()— which every listing/loading entry point (list(),list_commands(),list_profiles(),list_plugins(),load(),load_all()) calls unconditionally before any per-descriptor error isolation kicks in.Details
lib/python/base_cli/extensions.py:339-357:This is called unconditionally from
_metadata_descriptors()(extensions.py:273-284), which backslist()(:189-203) and thereforelist_commands()/list_profiles()/list_plugins()/load()/load_all()alike. Reproduced directly: registering one fake entry point withextras = ("base-cli-api-v1", "base-cli-api-v2")in a single group makesExtensionDiscovery.list_commands()raiseValueErroruncaught, even though the caller only asked about one group and no other entry point is involved.This directly contradicts the module's own isolation design:
load()(:238-241) wraps its per-descriptor load inexcept BaseExceptionand re-raises asExtensionLoadError, andload_all()(:252-261) individually catchesExtensionLoadError/ExtensionCollisionError/ExtensionCompatibilityErrorper descriptor so one bad extension can't take down the others — but none of that isolation exists for this particular validation error, and it fires even earlier, during metadata-only listing before any extension code is loaded or executed.Impact
One badly-packaged third-party plugin (a plausible packaging typo — declaring both an old and new
base-cli-api-v*extra rather than malicious intent) crashes command/profile/plugin discovery for a host application that never touched that plugin's code, likely at CLI startup. A consumer defensively catchingexcept ExtensionDiscoveryErroraround discovery calls won't catch this either, since the raised type isn't in that hierarchy.Suggested fix
Either validate/skip malformed entry points per-descriptor inside
_metadata_descriptors()(matching the isolationload_all()already provides), or raise anExtensionDiscoveryErrorsubclass instead of a bareValueErrorso it's at least catchable by the documented exception hierarchy, and havelist()skip and continue past the offending descriptor rather than aborting the whole call.