Closed bemyak closed 1 year ago
@gdey, thank you so much for the review!
I've tried to preserve the commits from the original feature author, as my impression was that they were already reviewed and approved. However, it might be easier if I redo the commit history and separate code cleanups from the actual feature code. What do you think?
Regarding caching, will it be enough to log a warning? Or should we fail the config validation? We don't support per-map caching, so the best thing we can do without implementing it is to skip maps with configured parameters.
Does this force anyone writing SQL to use $%d instead of '?'?
No, the numbered arguments are handled by the Tegola internals and are not exposed to the end user in any way. In maps' configuration, one uses only "tokens", like !PARAM1!
. In the parameter configuration, only ?
. The substitution will happen transparently.
What happens if one types a number that is generated in the SQL by mistake?
If that's just a mistake, Tegola will probably catch it during startup while executing inspectLayerGeomType
since the query isn't valid. If the geometry_type
was specified, that function is optional so that the parameter will be passed to the query and replaced with some value. I don't think we should protect against it. It's the same attack vector as if an admin would put DROP DATABASE
in the query :shrug:
We definitely must ensure that the documentation clearly states that only ?
is accepted as a placeholder, and numbered parameters here produce undefined behaviour.
I've tried to preserve the commits from the original feature author, as my impression was that they were already reviewed and approved. However, it might be easier if I redo the commit history and separate code cleanups from the actual feature code. What do you think?
I would say go ahead and rebase the code to separate out the clean-up from the actual feature code. This provides two benefits as I see it.
Regarding caching, will it be enough to log a warning? Or should we fail the config validation? We don't support per-map caching, so the best thing we can do without implementing it is to skip maps with configured parameters.
I feel we should fail on config validation. At least warn there that caching is being turned off due to maps with parameters.
Just skipping a map with parameters seems like the worst of both worlds, because the user has to remember which maps have parameters and which don't. The downside is that there isn't caching for any of the maps.
The PR is logging (with your review changes) when a map is not going to be cached at the time of tile buildup; this is going to inflate the logs (I believe) since this will have every time, an (uncached) tile is requested.
Failing at config validation time, or logging at that time the maps that will not be included in the cache may be better.
@dechristopher @mojodna @ARolek @ear7h opinions?
Does this force anyone writing SQL to use $%d instead of '?'?
No, the numbered arguments are handled by the Tegola internals and are not exposed to the end user in any way. In maps' configuration, one uses only "tokens", like
!PARAM1!
. In the parameter configuration, only?
. The substitution will happen transparently.
Okay, cool. Could not remember how we had implemented that.
What happens if one types a number that is generated in the SQL by mistake?
If that's just a mistake, Tegola will probably catch it during startup while executing
inspectLayerGeomType
since the query isn't valid. If thegeometry_type
was specified, that function is optional so that the parameter will be passed to the query and replaced with some value. I don't think we should protect against it. It's the same attack vector as if an admin would putDROP DATABASE
in the query shrug
I need to think about this.
We definitely must ensure that the documentation clearly states that only
?
is accepted as a placeholder, and numbered parameters here produce undefined behaviour.
:+1:
Changes Missing Coverage | Covered Lines | Changed/Added Lines | % | ||
---|---|---|---|---|---|
cmd/tegola/cmd/root.go | 0 | 1 | 0.0% | ||
atlas/map.go | 6 | 12 | 50.0% | ||
atlas/atlas.go | 0 | 7 | 0.0% | ||
provider/postgis/util.go | 18 | 25 | 72.0% | ||
cmd/tegola/cmd/cache/cache.go | 0 | 10 | 0.0% | ||
config/config.go | 76 | 86 | 88.37% | ||
provider/paramater_decoders.go | 0 | 12 | 0.0% | ||
provider/map_layer.go | 0 | 15 | 0.0% | ||
provider/postgis/postgis.go | 28 | 46 | 60.87% | ||
server/handle_map_layer_zxy.go | 12 | 34 | 35.29% | ||
<!-- | Total: | 218 | 396 | 55.05% | --> |
Files with Coverage Reduction | New Missed Lines | % | ||
---|---|---|---|---|
config/config.go | 1 | 77.61% | ||
provider/postgis/postgis.go | 1 | 62.07% | ||
<!-- | Total: | 2 | --> |
Totals | |
---|---|
Change from base Build dd8c61dfc: | 0.007% |
Covered Lines: | 5745 |
Relevant Lines: | 12676 |
Just summarizing my thoughts and findings on the caching
cache=true/false
param and ensure that all maps with custom params have it off.key=value
part for every custom parameter used. However, this value must be hashed to avoid attacks like specifying a value as ../../123
and reading tiles from another cache this waycmd/tegola/cmd/cache/cache.go
only affect the tegola cache
subcommand. I'll fix it when we decide what approach should be taken.cache=false
key to the map configuration and require it to be set for every map with custom paramsPersonally, I don't like №3 as the users don't have any saying in this; by adding this line, they just acknowledge the fact, so it's not a "configuration option".
@gdey, I rewrote the commit history. It should be much easier to follow it commit by commit now, as there are less back and forth changes.
Thank you for the great summation!
Possible solutions
1. Disable all caching if any custom parameter is configured
Sounds like this would be true Per Atlas and not for the entirety of Tegola instance.
2. Skip caching for maps that have custom parameters, printing a warning on startup
This seems to be the natural solution but will require documentation around people missing the warning on startup, and further clarification in the feature documentation.
3. Add a `cache=false` key to the map configuration and require it to be set for every map with custom params
Personally, I don't like №3 as the users don't have any saying in this; by adding this line, they just acknowledge the fact, so it's not a "configuration option". I agree, 3 is not a good solution, and add caching on a per map bases, should be out of scope for this PR.
@ARolek are we able to upgrade to go1.18, or do we still need to wait on that?
@ARolek are we able to upgrade to go1.18, or do we still need to wait on that?
Talk to @ARolek and we are fine with upgrading to go1.18, and can even move to go1.19.
Got an internal error when trying to build a lambda version of this branch. Has anyone else come across this issue?
Oh yea to clarify, this is after building tegola_lambda and uploading it to my lambda function on AWS that typically works when building the main branch. When opening the /capabilities url I get an internal error.
Thanks for giving it a try, @sjb-citian !
I haven't tested the lambda build. Are there any logs or a stacktrace so I could investigate?
@bemyak I rebuilt it this morning using the command specified in the read.me of the cmd/lambda folder and reconfigured my endpoint on AWS and it worked! Likely a build error on my part or I configured the endpoint incorrectly, either this branch definitely works with lambda.
@sjb-citian thanks for being diligent on this contribution, and again apologies for the slow response on my end. Regarding caching, I think we should go with:
- Skip caching for maps that have custom parameters, printing a warning on startup
This seems the most natural in my mind. If the user wants some caching, we can suggest they out a cache in front of tegola, like a CDN. Your breakdown of the complications with caching dynamic tiles is very correct. It opens up a whole new world of complexities that will likely need to be solved, but I think are beyond the scope of this initial enhancement.
I think the cache detail is the only final outstanding detail. What I would like to do next is the following:
main
. I just need to finish up some documentation and a few other minor details to do this.main
.main
so we can battle test it for a bit prior to the next tegola release. I'm excited to play with this feature. It has been long requested and again, I appreciate your diligence and patience. Your contribution is greatly appreciated!
@gdey , @ARolek , I added cache bypassing and the warning for maps with configured parameters.
Is there anything else remaining unresolved?
@ARolek, can I do something else here?
@bemyak nope! Action on me to get the release notes and documentation updates for the current version polished out. If you would like to help on that front I can push up a branch that you can help on. I'm mainly trying to cut over to using mvt_postgis in our readmes.
@bemyak can you rebase this branch against master
please?
@ARolek, done! I've just dropped two commits with the Go update and CI fix
@bemyak alright, I just cut the v0.16.0 version of tegola. Going to run the CI on this PR and then I will merge it in. Thanks again for the commitment and patience on this PR. I would like to let this sit in pre-release state for a bit so we can let the community give it a try.
PR now in master: https://github.com/go-spatial/tegola/commits/master. I'm going to open a discussion for anyone that needs help with the feature or has feedback. Onward!
@bemyak when opening this discussion, I realized the configuration instructions for the feature are only in the PR. Could you send in some README documentation to help guide future users?
@ARolek, thank you! I've opened a PR with the README update: https://github.com/go-spatial/tegola/pull/896
This PR is a successor of https://github.com/go-spatial/tegola/pull/795.
The main differences/features are:
int
1.18.3
~ (dropped, as upstream already uses 1.19)A user can define custom parameters on per-map basis like this:
When a request is received, a value of
QueryParameterValue
is constructed to hold the resulting parameter query (still with?
) and a value (parsed to the proper type).Then
(params map[string]QueryParameterValue) ReplaceParams(sql string, args *[]interface{}) string
function can be called which replaces parameters with positional arguments (e.g.,$1
,$2
) and fills an array with their values. This should prevent SQL injections.