Skip to content

Commit 3a036f2

Browse files
committed
Add initial work on execution policy
1 parent 05252d4 commit 3a036f2

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

src/pyapp/app/__init__.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ def my_command(
154154
"""
155155

156156
import argparse
157+
import enum
157158
import io
158159
import logging.config
159160
import os
@@ -172,6 +173,7 @@ def my_command(
172173
from ..events import Event
173174
from ..exceptions import ApplicationExit
174175
from ..injection import register_factory
176+
from ..compatability import is_user_root, ROOT_NAME
175177
from ..utils.inspect import import_root_module
176178
from . import init_logger
177179
from .argument_actions import * # noqa
@@ -181,6 +183,16 @@ def my_command(
181183
logger = logging.getLogger(__name__)
182184

183185

186+
class ExecutionPolicy(enum.IntEnum):
187+
"""Execution policy"""
188+
189+
Deny = 0
190+
Confirm = 10
191+
Warn = 20
192+
Allow = 30
193+
194+
195+
184196
def _key_help(key: str) -> str:
185197
"""Formats a key value from environment vars."""
186198
if key in os.environ:
@@ -259,6 +271,7 @@ def __init__( # noqa: PLR0913
259271
application_checks: str = None,
260272
env_settings_key: str = None,
261273
env_loglevel_key: str = None,
274+
root_execution_policy: ExecutionPolicy = ExecutionPolicy.Deny,
262275
):
263276
root_module = root_module or import_root_module()
264277
self.root_module = root_module
@@ -276,6 +289,8 @@ def __init__( # noqa: PLR0913
276289
self.ext_allow_list = ext_white_list
277290
self.ext_block_list = ext_block_list
278291

292+
self.root_execution_policy = root_execution_policy
293+
279294
# Determine application settings (disable for standalone scripts)
280295
if application_settings is None and root_module.__name__ != "__main__":
281296
application_settings = f"{root_module.__name__}.default_settings"
@@ -318,6 +333,19 @@ def application_summary(self) -> str:
318333
return f"{self.application_name} version {self.application_version} - {description}"
319334
return f"{self.application_name} version {self.application_version}"
320335

336+
def _apply_execution_policy(self):
337+
if is_user_root():
338+
match (self.root_execution_policy):
339+
case ExecutionPolicy.Deny:
340+
print(f"Execution denied as {ROOT_NAME} user", file=os.stderr)
341+
sys.exit(1)
342+
case ExecutionPolicy.Prompt:
343+
response = input(f"Warning: Executing as {ROOT_NAME}. Allow execution? [Y/N]")
344+
if response not in ("Y", "y"):
345+
sys.exit(1)
346+
case ExecutionPolicy.Warning:
347+
print(f"Warning: Executing as {ROOT_NAME}", file=os.stderr)
348+
321349
def _init_parser(self):
322350
# Create argument parser
323351
self.argument(

src/pyapp/utils/__init__.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
"""
55

66
import importlib
7+
import os
8+
import sys
79
import textwrap
810
from fnmatch import fnmatch
911
from typing import Any, Container, Sequence
@@ -19,6 +21,25 @@ def is_iterable(obj: Any) -> bool:
1921
return True
2022

2123

24+
if sys.platform.startswith("win"):
25+
from ctypes import windll
26+
27+
ROOT_NAME = "Administrator"
28+
29+
30+
def is_root() -> bool:
31+
"""This is a root user."""
32+
return bool(windll.shell32.IsUserAnAdmin()
33+
34+
else:
35+
ROOT_NAME = "root"
36+
37+
38+
def is_root() -> bool:
39+
"""This is a root user."""
40+
return bool(os.getuid() == 0)
41+
42+
2243
class CachedProperty:
2344
"""
2445
A property that is only computed once per instance and then replaces

0 commit comments

Comments
 (0)