66
77import yaml
88
9- from ogc .bblocks .transform import _PERMISSION_CHECKED_TYPES as _RISKY_TRANSFORM_TYPES
9+ from ogc .bblocks .transform import _PERMISSION_CHECKED_TYPES as _RISKY_TRANSFORM_TYPES , read_plugin_entries
1010_PERMISSIONS_FILE = 'permissions.json'
1111
1212
@@ -47,19 +47,6 @@ def _ask_yes_no(prompt: str) -> bool:
4747 print (" Please answer y or n." )
4848
4949
50- def _read_plugin_configs () -> list [dict ]:
51- """Read transform-plugins.yml without installing anything."""
52- plugins_path = Path ('transform-plugins.yml' )
53- if not plugins_path .exists ():
54- return []
55- try :
56- with open (plugins_path ) as f :
57- config = yaml .safe_load (f )
58- if not config or 'plugins' not in config :
59- return []
60- return config .get ('plugins' , []) or []
61- except Exception :
62- return []
6350
6451
6552def _scan_risky_transforms (items_dir : Path ) -> dict [str , list [tuple [str , str ]]]:
@@ -98,23 +85,68 @@ def _plugin_version_key(plugin: dict) -> str:
9885 return ',' .join (sorted (pip ))
9986
10087
88+ def _check_plugin_permissions (
89+ plugin_entries : list [dict ],
90+ cache_key : str ,
91+ cache : dict ,
92+ label : str ,
93+ ) -> tuple [set [str ], bool ]:
94+ """Prompt for permissions for a list of plugin entries.
95+
96+ Returns (allowed_modules, cache_was_modified).
97+ """
98+ cached : dict [str , str ] = dict (cache .get (cache_key , {}))
99+ allowed : set [str ] = set ()
100+ dirty = False
101+
102+ for plugin in plugin_entries :
103+ modules = plugin .get ('modules' , [])
104+ if isinstance (modules , str ):
105+ modules = [modules ]
106+ version_key = _plugin_version_key (plugin )
107+ pip_deps = plugin .get ('pip' , [])
108+ if isinstance (pip_deps , str ):
109+ pip_deps = [pip_deps ]
110+
111+ for module in modules :
112+ if cached .get (module ) == version_key :
113+ allowed .add (module )
114+ continue
115+
116+ _require_tty ()
117+ print ()
118+ print (f"╔══ { label } plugin permission required" )
119+ print (f"║ Plugin: { module } " )
120+ if pip_deps :
121+ print (f"║ Dependencies: { ', ' .join (pip_deps )} " )
122+ print ()
123+ if _ask_yes_no (f"Allow { label .lower ()} plugin '{ module } ' to be installed and run?" ):
124+ cached [module ] = version_key
125+ allowed .add (module )
126+ cache [cache_key ] = cached
127+ dirty = True
128+
129+ return allowed , dirty
130+
131+
101132def check_permissions (
102133 sandbox_dir : Path ,
103134 items_dir : Path ,
104- ) -> tuple [set [str ], set [str ]]:
135+ ) -> tuple [set [str ], set [str ], set [ str ] ]:
105136 """Check and prompt for permissions for risky transforms and plugins.
106137
107- Must be called before load_transform_plugins and before apply_transforms.
138+ Must be called before load_transform_plugins, load_validation_plugins,
139+ and apply_transforms.
108140 Returns:
109- allowed_transform_types: set of approved type strings
110- allowed_plugin_modules: set of approved module paths
141+ allowed_transform_types: set of approved type strings
142+ allowed_plugin_modules: set of approved transform plugin module paths
143+ allowed_validator_modules: set of approved validator plugin module paths
111144 Raises RuntimeError if stdin is not a TTY and permissions are needed.
112145 """
113146 cache = _load_cache (sandbox_dir )
114147 cache_dirty = False
115148
116149 cached_types : set [str ] = set (cache .get ('transform-types' , []))
117- cached_plugins : dict [str , str ] = dict (cache .get ('plugins' , {}))
118150
119151 # --- Transform types ---
120152 needed_types = _scan_risky_transforms (items_dir )
@@ -139,38 +171,19 @@ def check_permissions(
139171
140172 allowed_transform_types = cached_types
141173
142- # --- Plugins ---
143- plugin_configs = _read_plugin_configs ()
144- allowed_plugin_modules : set [str ] = set ()
145-
146- for plugin in plugin_configs :
147- modules = plugin .get ('modules' , [])
148- if isinstance (modules , str ):
149- modules = [modules ]
150- version_key = _plugin_version_key (plugin )
151- pip_deps = plugin .get ('pip' , [])
152- if isinstance (pip_deps , str ):
153- pip_deps = [pip_deps ]
154-
155- for module in modules :
156- if cached_plugins .get (module ) == version_key :
157- allowed_plugin_modules .add (module )
158- continue
174+ # --- Transform plugins ---
175+ allowed_plugin_modules , dirty = _check_plugin_permissions (
176+ read_plugin_entries ('transforms' ), 'plugins' , cache , 'Transform' ,
177+ )
178+ cache_dirty = cache_dirty or dirty
159179
160- _require_tty ()
161- print ()
162- print (f"╔══ Plugin permission required" )
163- print (f"║ Plugin: { module } " )
164- if pip_deps :
165- print (f"║ Dependencies: { ', ' .join (pip_deps )} " )
166- print ()
167- if _ask_yes_no (f"Allow plugin '{ module } ' to be installed and run?" ):
168- cached_plugins [module ] = version_key
169- allowed_plugin_modules .add (module )
170- cache ['plugins' ] = cached_plugins
171- cache_dirty = True
180+ # --- Validator plugins ---
181+ allowed_validator_modules , dirty = _check_plugin_permissions (
182+ read_plugin_entries ('validators' ), 'validator-plugins' , cache , 'Validator' ,
183+ )
184+ cache_dirty = cache_dirty or dirty
172185
173186 if cache_dirty :
174187 _save_cache (sandbox_dir , cache )
175188
176- return allowed_transform_types , allowed_plugin_modules
189+ return allowed_transform_types , allowed_plugin_modules , allowed_validator_modules
0 commit comments