-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcreate-python-sandbox
executable file
·120 lines (88 loc) · 3.7 KB
/
create-python-sandbox
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/python3
import os
from string import Template
DEFAULT_FIREJAIL_PATH = os.path.join(os.path.expanduser('~'), '.config', 'firejail')
DEFAULT_TEMPLATE_PATH = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
'python-env-template.profile',
)
DEFAULT_ENVS_PATH = os.path.join(os.path.expanduser('~'), 'envs')
class ProfileTemplate(Template):
delimiter = '€'
def read_template(path):
with open(path) as f:
return ProfileTemplate(f.read())
def write_profile(path, content):
with open(path, 'w') as f:
f.write(content)
def write_sandbox_dotfile(sandbox_name, working_dir):
"""This allows for shells to automatically enable the
sandbox once they find the file.
"""
path = os.path.join(working_dir, '.python-sandbox')
with open(path, 'w') as f:
f.write(sandbox_name + '\n')
return path
def resolve_working_dir(working_dir):
"""Make sure to get an absolute path or raise an error.
For example, if "." is supplied, it should resolve in the
current working dir as an absolute path since `.` would
not be valid as working dir in the template.
"""
return os.path.abspath(working_dir)
def resolve_env_dir():
"""Make sure that the user can permanently overwrite the place
where python environments are assumed to reside by the firejail
profile.
Method: Set `PYSANDBOX_ENVS_PATH` environment variable.
"""
return os.environ.get('PYSANDBOX_ENVS_PATH', DEFAULT_ENVS_PATH)
def main(args):
print(f'Loading template {args.template}.')
working_dir = resolve_working_dir(args.working_dir)
template_str = read_template(args.template)
profile_str = template_str.substitute({
'sandbox_name': args.sandbox_name,
'working_dir': working_dir,
'env_dir': resolve_env_dir(),
'HOME': os.path.expanduser('~'),
})
if not os.path.exists(DEFAULT_FIREJAIL_PATH):
os.makedirs(DEFAULT_FIREJAIL_PATH, exist_ok=True)
profile_name = f'python-env-{args.sandbox_name}.profile'
profile_path = os.path.join(DEFAULT_FIREJAIL_PATH, profile_name)
if os.path.exists(profile_path) and not args.force:
print('Profile already exists. Aborting.')
return 1
write_profile(profile_path, profile_str)
sandbox_dotfile = write_sandbox_dotfile(
args.sandbox_name,
working_dir,
)
print(f"Written profile to {profile_path}.")
print(f"Written {args.sandbox_name} to {sandbox_dotfile}.")
print("")
print(f"""Start your sandbox by running
firejail --profile=python-env-{args.sandbox_name} --tab bash
""")
if __name__ == "__main__":
import sys
from argparse import ArgumentParser
parser = ArgumentParser(
description="""Create a new python sandbox profile in the firejail
configuration directory given the name of the sandbox
and it's working directory (which gets full read-write)
access. The tool automatically places a `.python-sandbox` file with the
sandbox's name in the working directory.
For venv/conda/... environments, by default ~/envs/<sandbox name> is allowed.
To override the default directory where environments are supposed to be
stored, set the PYSANDBOX_ENVS_PATH environment variable.
"""
)
parser.add_argument('sandbox_name', type=str, help="name of sandbox (needs to be FS compatible)")
parser.add_argument('working_dir', type=str, help="Working directory of the sandbox")
parser.add_argument('--template', type=str, default=DEFAULT_TEMPLATE_PATH, help="Path to the firejail profile template")
parser.add_argument('-f', '--force', action='store_true', help="Force overriding the sandbox if it already exists")
args = parser.parse_args()
ret = main(args)
sys.exit(ret or 0)