[Fixes #14309] Generalize remote service type registration and auth handling - #14328
Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors service type handling by introducing a centralized ServiceTypeRegistry and enhances remote resource upload handlers (including COG, FlatGeobuf, 3D Tiles, and WMS) to support authentication configurations (AuthConfig) during validation and import. It also integrates authentication credentials with GDAL configuration options for remote metadata extraction. The review feedback highlights several improvement opportunities: implementing lazy initialization in ServiceTypeRegistry to avoid inefficient re-initialization and loss of dynamic registrations, and adding safety guards in BaseRemoteResourceHandler to prevent potential AttributeErrors when service_url, _exec, or options are None or empty.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #14328 +/- ##
===========================================
+ Coverage 34.71% 74.90% +40.18%
===========================================
Files 982 986 +4
Lines 60496 60862 +366
Branches 8247 8318 +71
===========================================
+ Hits 21002 45586 +24584
+ Misses 38332 13418 -24914
- Partials 1162 1858 +696 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR generalizes two previously hard-coded areas in GeoNode: (1) remote service type registration by introducing a dynamic ServiceTypeRegistry, and (2) remote authentication handling by moving AuthConfig extraction/reuse into the common remote resource handler and extending auth handlers to support GDAL configuration.
Changes:
- Introduces a dynamic service type registry (
ServiceTypeRegistry) and routesget_available_service_types()/ handler resolution through it. - Centralizes remote upload authentication extraction/reuse in
BaseRemoteResourceHandler(payloadauthentication→AuthConfig, rollback cleanup, reuse service-owned credentials). - Adds GDAL auth support via
AuthHandler.get_gdal_config()and applies it to remote GDAL-based handlers (COG / FlatGeobuf).
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| geonode/upload/handlers/remote/wms.py | Switches WMS auth lookup to the shared execution-based auth resolution. |
| geonode/upload/handlers/remote/tiles3d.py | Adds request auth usage for URL validation and import-time fetches; propagates auth_config_id into resource payload. |
| geonode/upload/handlers/remote/tests/test_wms.py | Updates tests for the new auth config creation API and the pre-processing-based auth reuse flow. |
| geonode/upload/handlers/remote/serializers/wms.py | Relies on the base remote serializer’s authentication field (no longer duplicated in WMS serializer). |
| geonode/upload/handlers/remote/flatgeobuf.py | Adds request auth for reachability checks and GDAL config option support via auth handlers. |
| geonode/upload/handlers/remote/cog.py | Adds request auth for reachability checks and GDAL config option support via auth handlers. |
| geonode/upload/handlers/common/test_remote.py | Adds coverage for common remote auth extraction + rollback deletion behavior. |
| geonode/upload/handlers/common/serializer.py | Adds and validates authentication on the base remote upload serializer. |
| geonode/upload/handlers/common/remote.py | Centralizes auth config extraction, rollback cleanup, service matching, and request auth helpers. |
| geonode/upload/datastore.py | Passes execution_id into is_valid_url() to allow authenticated validation. |
| geonode/thumbs/tests/test_unit.py | Updates tests to the new create_auth_config(payload) signature. |
| geonode/services/tests.py | Updates tests to patch the registry-based handler lookup and adds registry-specific unit tests. |
| geonode/services/serviceprocessors/registry.py | Adds the new dynamic service type registry implementation. |
| geonode/services/serviceprocessors/init.py | Switches service type listing/handler lookup to the registry. |
| geonode/services/models.py | Makes service type choices dynamic at runtime and avoids KeyError in ptype. |
| geonode/services/migrations/0060_alter_service_type.py | Alters Service.type choices to be dynamically provided. |
| geonode/services/forms.py | Uses dynamic service type choices from get_service_type_choices. |
| geonode/services/apps.py | Initializes the service type registry during app startup. |
| geonode/security/tests.py | Updates tests and adds coverage for GDAL config generation in the basic auth handler. |
| geonode/security/auth_handlers.py | Adds get_gdal_config() and updates create_auth_config() to accept a payload dict. |
Comments suppressed due to low confidence (1)
geonode/services/serviceprocessors/init.py:50
get_service_handler()now directly looks up a handler class inservice_type_registryand instantiates it. Forservice_typevalues likeAUTO/OWS(and any unknown type),service_type_registry.get_handler_class()returnsNone, which will raise aTypeError: 'NoneType' object is not callable. This breaks the function’s documented behavior (“guessed from”) and makes callers vulnerable to hard crashes instead of a controlled error or auto-detection.
def get_service_handler(base_url, service_type=enumerations.AUTO, service_id=None, *args, **kwargs):
"""Return the appropriate remote service handler for the input URL.
If the service type is not explicitly passed in it will be guessed from
"""
if entry := service_cache.get(base_url):
return entry
handler = service_type_registry.get_handler_class(service_type)
try:
service_handler = handler(base_url, service_id, *args, **kwargs)
service_cache.set(service_handler.url, service_handler, settings.SERVICE_CACHE_EXPIRATION_TIME)
except Exception as e:
logger.exception(e)
logger.exception(msg=f"Could not parse service {base_url}")
raise
return service_handler
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Fixes #14309
Checklist
For all pull requests:
The following are required only for core and extension modules (they are welcomed, but not required, for contrib modules):
Submitting the PR does not require you to check all items, but by the time it gets merged, they should be either satisfied or inapplicable.