deno: Deno.openPlugin resolution is not inline with the rest of Deno
Just played around with the new modules and found some inconsistencies with the rest of Deno.
- can not resolve
file://${path}paths (resolves to${cwd}/file:/${path}) - can not resolve external paths (
http://andhttps://) - relative paths resolve relative to ${cwd} and not relative to the module path
The resolution algorithm that is used by import should probably also be used for plugins.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 16 (11 by maintainers)
I don’t think is
importis good for this. Different platforms use different plugins, so dynamic import makes more sense.Also, I support making
openPluginaccepts http URL and caching plugins to$DENO_DIR/plugins.Resolving and loading plugins like modules would be nice, but there are some difficulties here. The underlying c function
dlopenthat supports the entire plugin functionality can only accept file paths.I have considered emulating the underlying function of
dlopen(load file contents to ram, inform kernel this memory space is executable, dynamically link resources from the memory namespace, etc). This might be a valid option ,but would add a significant amount of complexity and would require specific support on our end for each kernel.Maybe a simpler approach here is to cache the plugin file like we do compiled JavaScript. Either way downloading a file and loading directly into memory as executable presents a lot of security concerns.
A potential third approach of adding custom compiler support and building a custom cargo/rust compiler might be a good solution here as well. I like this solution the most, since a custom compiler could actually generate TypeScript bindings to go on top of said plugins. This also avoids downloading a compiled binary and loading directly to memory. When I first started working on plugins I thought that it would be cool if we could just import a
cargo.tomlfile and compile like we do TypeScript, but I quickly realized how complex that would be(especially for http/https imports). A solution like that would have been almost as much complexity as the rest of deno at the time for a feature that isn’t even the main function of deno. It makes a lot more sense for something like this to be it’s own project.The existing plugin system is intended to be very simple it’s primary goal is to enable calling custom native code from the deno runtime. It’s not a framework. Just a simple way to call into custom rust code. While I would like to be able to resolve plugins like imports it’s not possible to determine the caller from the rust side like a referrer in a import resolution. For now I think the best we can really expect is some tooling in std to make this a little easier and maybe some tweaks to resolution to allow absolute full paths(
file:///some/path). I have found usingimport.meta.urlplusjointo be a pretty good solution right now. I have some working code using what I would consider standard practices in the form of deno_in_deno(check out theuse_new_plugin_apibranch for more up to date examples).It’s not a JS module, module resolution is its own thing. While URL plugins are interesting 😄, I think it’s properly consistent with other FS ops.
I don’t see why those shouldn’t support the
file:protocol, though.I was against applying module semantics when plugins are brought in with a function call.
Since this is maybe going in that direction, I’m perfectly okay with treating them as modules if they are actually brought in using the import syntax:
import { some_op as someOp } from "./plugins/libsome_op.so"assuming there are no other issues with that.I think we should go for the approach where we download into a folder in DENO_DIR and then also load them from there. I think manually loading the contents into memory, marking it as exec and directly calling the
dlopensyscall is too complicated.If we build remote resolution of plugins right into the ‘secure’ part of Deno then this makes the experience of using plugins simpler for users. We can use the same caching algorithms as JS imports, we can respect the
--no-remoteflag, we can respect the--reloadflag, and all of the cached deps (js, ts, wasm and plugins) can all be stored in the same dir - DENO_DIR. Implementing this instdwould just require us to expose all of these flags to the user via ops. It seems nicer to just use the existing rust code. We might even be able to integrate this into the lock file which would be very nice.I don’t think there are any more security implications in running with
--allow-pluginthan there are using--allow-run.--allow-runcan also execute arbitrary binaries. Specifying either of these permissions gives you full system access and all of the Deno security promises are gone. I understand loading a dynamic lib is more scary as you are right inside of the Deno process, but ey, that’s just one of the tradeoffs you have with plugins - all security is gone.