-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Additional Mango-based update handler / VDU functionality #1554
Comments
Got to thinking more about this one in the shower. Here's a sample Mango-like document structure for a combined VDU/update handler that would capture all of the above: {
"queries": [
{
"name": "sensor_name",
"selector": {
"type": "sensor",
"ip_address": "$doc.ip_address"
},
"fields": ["name"],
...
}
],
"fields": {
"whitelist": ["type", "datetime", "ip_address", "station_name", "temperature", "RH%", "rain_gauge", "wind.speed", "wind.direction", "light", "battery.voltage", "battery.current", "line.voltage", "line.current", "solar.voltage", "solar.current", "register_total"],
"blacklist": ["battery.wattage", "rain_gauge.*"],
"formats": {
"type": ["sensor_reading"],
"datetime": {
"$or": {
"$format": "$iso8601",
"$format": "$unixepoch",
"$regex": "(\\d{2})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})"
}
},
"battery.voltage": "$float",
"battery.current": "$float",
"register_total": { "$regex": "^\\$\\d{1,9}\\.\\d{2}$" },
"wind.direction": {"$or": ["N", "NE", "E", "SE", "S", "SW", "W", "NW"]}
...
}
},
"patch": [
{ "op": "add", "path": "/", "value": { "name": "$query:sensor_name.name" } },
{ "op": "move", "from": "/ip-address", "path": "/ip_address" },
{ "op": "add", "path": "/", "value": { "server_datetime": "$server_time.iso8601" } },
...
]
} Comments:
Just some food for discussion. |
IMO the transform:[
{
selector:{ // Mango selector for list of actions
type: { $neq: "whatever"}
},
actions: [ // List of actions
["stop"]
]
},
// Next item, used if we didn‘t stop processing
{selector:{ stamp: { $format:'Int', $gt: 1234567890123}}},
actions: [
["set", ".ip", ":peer" ],
["swap", ".a.0", ["a", "1"]],
["del", ".x.y.z" ]
]}
//...
] Actions are pretty self-explanatory, so no need to use obj keys. Objects as This also replaces Also syntax It all seems unexpectedly reasonable. I’ll try to write down some of our _updates in this way, to compare readability and to understand other json-induced benefits/penalties. And I couldn‘t comprehend what |
Sorry, I hit submit too quickly. The As for The pre-update-Mango-query stuff is speculative; there may well be pushback from the db core team on making update functions a little too clever and slow since they're now performing a read before a write. We'll see. I think the proposal is valuable even without that specific functionality. |
I really like where this is going, great first draft! Quick initial notes up top:
One further aspect that we should discuss the other use of VDUs. To recap, VDUs are used to enforce document schema (this is handled in this draft) and authorisation, where check doc contents against the context of http:https://docs.couchdb.org/en/stable/ddocs/ddocs.html#vdufun For Example: function (newDoc, oldDoc, userCtx) {
// in an authenticated request, userCtx.user is the authenticated username
// so we can:
if (oldDoc.author != userCtx.name) {
throw({ forbidden: 'you can’t update other user’s docs.' })
}
} In addition, there is a fourth parameter, the function (newDoc, oldDoc, userCtx, secObj) {
if (secObj.members.names.indexOf(userCtx.name) === -1) {
throw({ forbidden: 'you can’t update if you’re not a member.' }) // contrived example, you wouldn’t get to this part in the first place, because the _security check comes first, but you should get what is meant
}
} We could argue that this could co-incide with the security overhaul, which would take care of any authentication, and I’m happy to discuss this separately if needed, I just wanted to bring this up. Maybe the draft can be amended, so {
"fields": {
"whitelist": ["type", "datetime", "ip_address", "station_name", "temperature", "RH%", "rain_gauge", "wind.speed", "wind.direction", "light", "battery.voltage", "battery.current", "line.voltage", "line.current", "solar.voltage", "solar.current", "register_total"],
"blacklist": ["battery.wattage", "rain_gauge.*"],
"formats": {
"type": ["sensor_reading"],
"datetime": {
"$or": {
"$format": "$iso8601",
"$format": "$unixepoch",
"$regex": "(\\d{2})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})"
}
},
"battery.voltage": "$float",
"battery.current": "$float",
"register_total": { "$regex": "^\\$\\d{1,9}\\.\\d{2}$" },
"wind.direction": {"$or": ["N", "NE", "E", "SE", "S", "SW", "W", "NW"]}
...
}
},
"authorisation": [
{
"author": { "$eq" : "$userCtx.name" },
"throw": "you can’t update other user’s docs."
]}
} where the line |
I like this idea, and especially the ability to use multiple docs of this format to enforce rules such as "only users with role The I'm flexible on what lives where in the actual doc, would like to see some other opinions as well. I would say that for The alternative is to prefix all document fields with |
yeah not a fan of That might dovetail into my next proposal (that I’ll open a new ticket for), to add string manipulation funs to Mango, those then would follow the same lead, say |
@janl should your JSON snippet be (i..e, with the
Also, I used American spelling for "authorization". Suggestion:
Questions:
|
@mikerhodes good catch, that's a typo! |
@mikerhodes asks:
Idea 1: Maybe we need a version field, regardless of what we do with this, if not specified we assume it's the version of whatever the current runtime is The latter 2 come from electronic door locks that generally come with a user-configurable setting for this.
Well, in Apache CouchDB, there are no such things as write-only users to my knowledge. Are you talking about a Cloudant-specific thing, or something that might come in with #1504 ? I was imagining that if any of the tests failed (pre-@janl's change) a generic response would be provided, along the lines of The other option would be to provide a Thanks for the discussion! |
Cloudant has write-only, but I did think that it'd likely come in with any access rewrite as it's definitely a useful thing. |
I‘ve tried to re-write several real simple _update fns with proposed syntax. My observations:
AFAIK more risk is to make them dumb and cryptic as old-style rewrites ) Here is a set of existing tools of the sort, hope it can be a source for further inspiration https://stackoverflow.com/questions/1618038/xslt-equivalent-for-json/49011455#49011455 |
@ermouth do you have an example? |
@janl latest json schema has if/then/else http:https://json-schema.org/draft-07/json-schema-release-notes.html |
I'll suggest the obvious: that the guards be declarative and mango selectors. I think "condition" may be the right term for the authorization's actual business logic (might be a better term from the authorization literature, but it escapes me right now). Combining the suggestion to split out the authz section into three fields:
|
@mikerhodes I already suggested exactly same approach (using Mango selectors as guards/conditions), see above, however it was assumed too clever. Nice to see this obvious and practical way came not only in my head. What is the difference between |
@ermouth I think I misunderstood what you were proposing...probably a language barrier. It's clearer to me now. I think the guard is checked first, to make sure that the document would even have the field in question, and then the condition is checked. This would translate to JS in such a way: if (doc.type === "post") {
if (doc.author != userCtx.name) {
throw("you can't update other users' docs.")
}
} Am I right @mikerhodes ? And if so, perhaps your |
@wohali Yes, that's the basic logic. I think my condition logic is the wrong way around, because I would say that the if (doc.type === "post") { // i.e., "if <guard condition>"
if (! (doc.author == userCtx.name)) { // i.e., "if not <condition>"
throw("you can't update other users' docs.")
}
} @ermouth I can see that you could combine the guard and the condition into a single clause quite easily given they are both Mango selectors. I just find that the logical distinction of "the types of thing this authorisation decision applies to" (guard) and "the authorisation condition itself" (condition) makes things more clear. As to whether |
I wrote up a gist describing a possible What do y'all think? |
After digging into Mango's source and discussing this feature with folks, I think only one new method+endpoint is necessary to facilitate Mango VDUs: VDUs in this case are Mango indexes with the
I suggest this approach because VDU selectors in this formulation can use string substitution to access For example: {
"index": {
"guard": { "type": "article" },
"condition": {
"name": { "$in": "$secObj.members.names" },
"$or": {
"$not": { "$exists": "$oldDoc.author" },
"author": { "$eq": "$oldDoc.author" }
}
}
},
"type": "vdu"
} Does that make sense? Seem reasonable? |
Good to see some movement here, and nice write up. It feels a little odd to overload the term Another reason to avoid overloading the index term is that the VDU index section has a very different schema to a normal Mango index section too, which makes writing client libraries pretty tough (especially those libraries that map JSON to concrete types, which is a primary utility of a client library over raw HTTP calls IMO). |
That makes sense, that overloading I still like the guard-condition syntax for the VDU, where the guard and condition are selectors with different expectations and abilities. I'll go for another few dives into the source and see if I can't figure out a PR. |
Diana, this is really cool. If you need some help understanding the code, let me know. I’m happy to help.
…________________________________
From: Diana Thayer <[email protected]>
Sent: Wednesday, January 23, 2019 6:11 PM
To: apache/couchdb
Cc: Subscribed
Subject: Re: [apache/couchdb] Additional Mango-based update handler / VDU functionality (#1554)
That makes sense, that overloading /_index with a process that doesn't involve indexing does indeed not make sense. Thanks for that reality check :)
I still like the guard-condition syntax for the VDU, where the guard and condition are selectors with different expectations and abilities. I'll go for another few dives into the source and see if I can't figure out a PR.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub<#1554 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/AAK9AsNusxhLYYBUvmFubc5WpW1MulBUks5vGIm_gaJpZM4V5aai>.
|
@garrensmith That's very much appreciated. I'd love for some pointers on which files will contain pertinent code, functions I might have to edit or copy, etc. Otherwise I'm just stumbling through the source and hitting my local couch with requests, hoping the responses change in response to my actions. |
I'm going to try and leave some ideas on how to implement this. The one thing I've noticed is that this is quite a large amount of work, so I think try and break it up into smaller usable PR's. I also think it is worth creating a RFC for this with all the information on this and add in the gist so that its in 1 central place. I would start on the transform section first. That section could possibly be used in the mango query section. We could take a document we want to index and then transform it before adding it to the index. This has been a requested feature. For I think it might be best to create a new mango_vdu_selector or something file that uses parts of mango_selector and does all the validation and transformation of a document based on the syntax. Saving/creating/getching of VDU's: I hope that helps a little. |
I swear I thought I had mentioned this already, but apparently not on this thread. I’d leave the transform bits out of this proposal and focus on the VDU part: validate that a doc looks like what you want it to be and comes from someone you want it to be. I’d leave mango-like syntax for doc transformation to #1559. |
+1 to reducing the scope of this work.
…________________________________
From: Jan Lehnardt <[email protected]>
Sent: Wednesday, February 20, 2019 12:57 PM
To: apache/couchdb
Cc: garren smith; Mention
Subject: Re: [apache/couchdb] Additional Mango-based update handler / VDU functionality (#1554)
I swear I thought I had mentioned this already, but apparently not on this thread.
I’d leave the transform bits out of this proposals on focus on the VDU part: validate that a doc looks like what you want it to be and comes from someone you want it to be.
I’d leave mango-like syntax for doc transformation to #1559<#1559>.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#1554 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/AAK9Alq3mMGDv4fIXGZ8FmeiK12tIDM3ks5vPSo3gaJpZM4V5aai>.
|
This ticket is intended to gather ideas for what other sorts of update handler / VDU functionality we could add to Mango to provide a declarative replacement for JS-based update handlers and VDUs. This is intended as a "blue-sky" ticket to gather ideas that can be implemented simply in a declarative fashion.
From #1534, I wrote:
Extracting:
req
objectreq
objectreq
field value to a key:value pair (or JSON Patch) to insert?type
is string, fielddate
is ISO datetime|UNIX epoch, etc.)"$###.##"
or an integer must be within a certain range)source
and extracting the fieldip_address
, then only allowing documents to come through that have a matchingreq.ip_address
(for example).The text was updated successfully, but these errors were encountered: