Summary
Let a server-backed layer be published as a view: a saved attribute and spatial filter applied on the server, so a recipient sees a defined subset of the data and cannot widen it. Includes the special case where the filter is "only the features you created".
Why
Filtering today is a display decision. A MapLibre filter expression, a where clause in a layer's configuration, a definition query set in the UI — all of them live in the project file, are applied in the client, and are trivially removed by whoever holds the project. That is entirely appropriate for cartography and useless for access control.
The consequence is that the answer to "can I share this dataset but only the part that concerns this partner?" is currently no. The workarounds are to physically extract a copy (which immediately goes stale and multiplies the number of places the data lives) or to not share at all.
Two shapes come up repeatedly:
- Subset by attribute or extent — one county's records out of a statewide table; this year's out of a decade's; non-sensitive categories only.
- Only your own features — a field-collection or crowd-reporting workflow where many people write to one table and each should see and edit their own rows, with a supervisor seeing all of them. This is the pattern behind most multi-user data-collection requests, and it is unbuildable today.
Proposal
1. A view definition on server-backed layers
For layers whose data is fetched per request — PostGIS through the sidecar and through martin, and sidecar-backed raster/vector endpoints — allow the layer to reference a named, server-stored view definition:
- an attribute predicate (a validated
where, not raw client SQL);
- an optional spatial predicate (a bounding box or clip polygon);
- an optional field list, which is the field-level visibility issue's mechanism.
The definition is stored and applied server-side. The client is told it is looking at a view and what the filter is, so the UI can say so honestly, but changing the client's copy changes nothing.
2. Own-features-only mode
A view definition mode that resolves to "rows whose creator matches the authenticated caller", plus a role that is exempt (supervisor sees everything). This depends on editor tracking to have a creator column at all, and on real sign-in to have an identity to match against — sequence it after both.
3. Where the boundary is
State this in the docs and in the UI: view definitions apply to layers the server serves per request. A local file, an embedded GeoJSON, a COG or PMTiles the browser range-reads directly, or any layer already fully resident in the client cannot be subset this way — for those, the only real answer is to publish a physically derived subset. Do not offer the feature on layer types where it would be theater.
Scope notes
- Mostly
backend/geolibre_server/geolibre_server/app/postgis.py: postgis_read and postgis_write both need to compose the view predicate into every query, and postgis_write must additionally refuse writes that would place a row outside the view.
- Predicates must be built as parameterized SQL, never string-concatenated from client input. The existing
_sanitize_error / _validate_postgis_target care in that module is the standard to match.
- Needs the per-layer capability set as the place to attach the view reference.
- For martin-served tiles, the equivalent is a dedicated published function/view rather than a runtime predicate; note the difference rather than pretending one mechanism covers both.
Effort
Wishlist. This is the deepest item in the access-control umbrella and the one most worth getting right slowly.
Part of #1665 (access control umbrella).
Summary
Let a server-backed layer be published as a view: a saved attribute and spatial filter applied on the server, so a recipient sees a defined subset of the data and cannot widen it. Includes the special case where the filter is "only the features you created".
Why
Filtering today is a display decision. A MapLibre filter expression, a
whereclause in a layer's configuration, a definition query set in the UI — all of them live in the project file, are applied in the client, and are trivially removed by whoever holds the project. That is entirely appropriate for cartography and useless for access control.The consequence is that the answer to "can I share this dataset but only the part that concerns this partner?" is currently no. The workarounds are to physically extract a copy (which immediately goes stale and multiplies the number of places the data lives) or to not share at all.
Two shapes come up repeatedly:
Proposal
1. A view definition on server-backed layers
For layers whose data is fetched per request — PostGIS through the sidecar and through martin, and sidecar-backed raster/vector endpoints — allow the layer to reference a named, server-stored view definition:
where, not raw client SQL);The definition is stored and applied server-side. The client is told it is looking at a view and what the filter is, so the UI can say so honestly, but changing the client's copy changes nothing.
2. Own-features-only mode
A view definition mode that resolves to "rows whose creator matches the authenticated caller", plus a role that is exempt (supervisor sees everything). This depends on editor tracking to have a creator column at all, and on real sign-in to have an identity to match against — sequence it after both.
3. Where the boundary is
State this in the docs and in the UI: view definitions apply to layers the server serves per request. A local file, an embedded GeoJSON, a COG or PMTiles the browser range-reads directly, or any layer already fully resident in the client cannot be subset this way — for those, the only real answer is to publish a physically derived subset. Do not offer the feature on layer types where it would be theater.
Scope notes
backend/geolibre_server/geolibre_server/app/postgis.py:postgis_readandpostgis_writeboth need to compose the view predicate into every query, andpostgis_writemust additionally refuse writes that would place a row outside the view._sanitize_error/_validate_postgis_targetcare in that module is the standard to match.Effort
Wishlist. This is the deepest item in the access-control umbrella and the one most worth getting right slowly.
Part of #1665 (access control umbrella).