zopefoundation / Products.PythonScripts

Provides support for restricted execution of Python scripts in Zope.
Other
6 stars 10 forks source link

allowed_modules per instance #60

Closed georgpfolz closed 1 year ago

georgpfolz commented 1 year ago

Is there a way to have allowed_module('a_python_module') on a per-instance base?

It works the way it's described in the README file (allowing modules for a Zope installation), but I'd prefer to allow some modules only for some specific Zope instances. I tried to place the 'GlobalModules' dummy module under myinstance/Products or myinstance/lib/python/Products but to no avail. I guess this may have worked in (much) older Zope versions, when the Products folder in the instance home was still used.

I'm aware that I can allow Python modules in a Zope Product, but then it's allowed in all instances using that product, which is also not what I need.

d-maurer commented 1 year ago

Georg Pfolz wrote at 2023-2-27 01:12 -0800:

Is there a way to have allowed_module('my_module') on a per-instance base?

The allowed_module modifies a (process) global data structure. Thus, it is sufficient to ensure that it is executed only in the instances you want, e.g. via an envvar or the client information.

-- Dieter

dataflake commented 1 year ago

Can you define "instance"? For me an "instance" is a Python process running out of a Zope installation that was created via pip or buildout. Could it be that for you "instance" means a folder in the ZODB instead? In that case you cannot have different allow_module values. The result of a call to allow_module is global for the entire process.

ale-rt commented 1 year ago

I am not sure it will work for your use case but I am using the buildout recipe plone.recipe.zope2instance to do something similar.

There is an initialization option where you can add some Python code, e.g.:

[instance]
initialization =
    import sentry_sdk
    sentry_sdk.utils.MAX_STRING_LENGTH = 4096

That code is executed before starting the instance:

$ tail bin/instance

import sentry_sdk
sentry_sdk.utils.MAX_STRING_LENGTH = 4096

import plone.recipe.zope2instance.ctl

if __name__ == '__main__':
    sys.exit(plone.recipe.zope2instance.ctl.main(
        ['-C', '.../parts/instance/etc/zope.conf', '-p', '.../parts/instance/bin/interpreter', '-w', '.../parts/instance/etc/wsgi.ini']
        + sys.argv[1:]))

In your case you could do:

[instance1]
initialization =
     from AccessControl.SecurityInfo import allow_module
     allow_module("instance1_module")
[instance2]
initialization =
     from AccessControl.SecurityInfo import allow_module
     allow_module("instance2_module")

I hope this helps!

georgpfolz commented 1 year ago

@dataflake

Can you define "instance"? For me an "instance" is a Python process running out of a Zope installation that was created via pip or buildout. Could it be that for you "instance" means a folder in the ZODB instead? In that case you cannot have different allow_module values. The result of a call to allow_module is global for the entire process.

I mean a "Zope instance" created via mkwsgiinstance.

dataflake commented 1 year ago

The basic mkwsgiinstance script is not very flexible for setups like this. It essentially assumes that each Python virtual environment serves a single Zope instance which loads all packages installed into the virtual environment. It has no hooks for specialized initialization code like zc.buildout has, either. You should consider switching to zc.buildout and following the example @ale-rt showed you.

georgpfolz commented 1 year ago

@ale-rt @dataflake

I do not use Plone nor zc buildout, so I cannot use ale-rt's solution. But the initialization of instance1 and instance2 as described by him is probably what I want. So it would be interesting where these recipe settings end up in the finalized Zope instance.

dataflake commented 1 year ago

plone.recipe.zope2instance has no dependencies on Plone at all. Yes, you can use this solution in a straight Zope setup. Matter of fact the majority of Zope users go this route.

The initialization code is injected directly into the specialized start/stop scripts plone.recipe.zope2instance creates. This cannot be replicated with a basic mkwsgiinstance setup.

georgpfolz commented 1 year ago

@dataflake

The initialization code is injected directly into the specialized start/stop scripts plone.recipe.zope2instance creates. This cannot be replicated with a basic mkwsgiinstance setup.

Thank you! That pointed me in the right direction!

I use my own customized bin/runwsgid start/stop scripts (which I start as daemon in rc.d on FreeBSD). These are the right place to insert the allow_module statements!