croom 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- croom/__init__.py +5 -0
- croom/helpers.py +8 -0
- croom/room.py +2 -0
- croom/roomspec.py +134 -0
- croom-0.1.0.dist-info/METADATA +52 -0
- croom-0.1.0.dist-info/RECORD +9 -0
- croom-0.1.0.dist-info/WHEEL +4 -0
- croom-0.1.0.dist-info/entry_points.txt +2 -0
- croom-0.1.0.dist-info/licenses/LICENSE +10 -0
croom/__init__.py
ADDED
croom/helpers.py
ADDED
croom/room.py
ADDED
croom/roomspec.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import shlex
|
|
3
|
+
import tomllib
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from .helpers import is_valid_url
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class Checksum:
|
|
12
|
+
"""represents a checksum to verify a downloaded artifact against"""
|
|
13
|
+
|
|
14
|
+
checksum: str
|
|
15
|
+
type: str = "sha256"
|
|
16
|
+
|
|
17
|
+
def check(self, b: bytes) -> bool:
|
|
18
|
+
"""check the stored checksum against bytes"""
|
|
19
|
+
h = hashlib.new(self.type)
|
|
20
|
+
h.update(b)
|
|
21
|
+
return h.hexdigest().strip().lower() == self.checksum.strip().lower()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class RoomSpecSource:
|
|
26
|
+
checksum: Checksum
|
|
27
|
+
url: str
|
|
28
|
+
directory: Path | None = None
|
|
29
|
+
|
|
30
|
+
def __post_init__(self):
|
|
31
|
+
if not is_valid_url(self.url):
|
|
32
|
+
raise ValueError(f"invalid url: {self.url}")
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def from_dict(cls, d: dict) -> "RoomSpecSource":
|
|
36
|
+
"""create a RoomSpecSource from a dict"""
|
|
37
|
+
dchecksum = d.get("checksum", {})
|
|
38
|
+
checksum_type = dchecksum.get("type", None)
|
|
39
|
+
checksum_value = dchecksum.get("value", None)
|
|
40
|
+
checksum = Checksum(checksum_value, checksum_type)
|
|
41
|
+
|
|
42
|
+
url = d.get("url", "")
|
|
43
|
+
directory = d.get("directory", None)
|
|
44
|
+
|
|
45
|
+
if not is_valid_url(url):
|
|
46
|
+
raise ValueError(f"invalid url: {url}")
|
|
47
|
+
|
|
48
|
+
return cls(checksum, url, Path(directory) if directory else None)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class RoomSpecConfiguration:
|
|
53
|
+
symlink_resolv: bool = True
|
|
54
|
+
can_persist: bool = True
|
|
55
|
+
can_cache: bool = False
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def from_dict(cls, d: dict) -> "RoomSpecConfiguration":
|
|
59
|
+
"""create a RoomSpecConfiguration from a dict"""
|
|
60
|
+
return cls(
|
|
61
|
+
bool(d.get("symlink-resolv", True)),
|
|
62
|
+
bool(d.get("can-persist", True)),
|
|
63
|
+
bool(d.get("can-cache", False)),
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass
|
|
68
|
+
class PostExtractStep:
|
|
69
|
+
name: str
|
|
70
|
+
optional: bool = False
|
|
71
|
+
requires_reload: bool = False
|
|
72
|
+
ignore_fail: bool = False
|
|
73
|
+
command: list[str] = field(default_factory=list)
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def from_dict(cls, d: dict) -> "PostExtractStep":
|
|
77
|
+
"""create a PostExtractStep from a dict"""
|
|
78
|
+
name = d.get("name", "")
|
|
79
|
+
if not name.strip():
|
|
80
|
+
raise ValueError("name not found")
|
|
81
|
+
|
|
82
|
+
optional = bool(d.get("optional", False))
|
|
83
|
+
requires_reload = bool(d.get("requires-reload", False))
|
|
84
|
+
ignore_fail = bool(d.get("ignore-fail", False))
|
|
85
|
+
scommand = d.get("command", "")
|
|
86
|
+
if not scommand.strip():
|
|
87
|
+
raise ValueError("command not found")
|
|
88
|
+
command = shlex.split(scommand)
|
|
89
|
+
|
|
90
|
+
return cls(name, optional, requires_reload, ignore_fail, command)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@dataclass
|
|
94
|
+
class RoomSpec:
|
|
95
|
+
"""represents a room spec"""
|
|
96
|
+
|
|
97
|
+
name: str
|
|
98
|
+
version: str
|
|
99
|
+
|
|
100
|
+
source: RoomSpecSource
|
|
101
|
+
configuration: RoomSpecConfiguration
|
|
102
|
+
postextract: list[PostExtractStep] = field(default_factory=list)
|
|
103
|
+
|
|
104
|
+
@classmethod
|
|
105
|
+
def from_toml(cls, f: Path) -> "RoomSpec":
|
|
106
|
+
"""create a RoomSpec from a TOML file"""
|
|
107
|
+
with open(str(f), "rb") as fp:
|
|
108
|
+
d = tomllib.load(fp)
|
|
109
|
+
return cls.from_dict(d)
|
|
110
|
+
|
|
111
|
+
@classmethod
|
|
112
|
+
def from_dict(cls, d: dict) -> "RoomSpec":
|
|
113
|
+
"""create a RoomSpec from a dict"""
|
|
114
|
+
name = d.get("roomspec", {}).get("name", "").strip()
|
|
115
|
+
version = d.get("roomspec", {}).get("version", "").strip()
|
|
116
|
+
|
|
117
|
+
if not name:
|
|
118
|
+
raise ValueError("name not found")
|
|
119
|
+
|
|
120
|
+
if not version:
|
|
121
|
+
raise ValueError("version not found")
|
|
122
|
+
|
|
123
|
+
dsrc = d.get("source", {})
|
|
124
|
+
rsrc = RoomSpecSource.from_dict(dsrc)
|
|
125
|
+
|
|
126
|
+
dcfg = d.get("configuration", {})
|
|
127
|
+
rcfg = RoomSpecConfiguration.from_dict(dcfg)
|
|
128
|
+
|
|
129
|
+
dpsteps = d.get("postextract", [])
|
|
130
|
+
psteps = []
|
|
131
|
+
for dpstep in dpsteps:
|
|
132
|
+
psteps.append(PostExtractStep.from_dict(dpstep))
|
|
133
|
+
|
|
134
|
+
return cls(name, version, rsrc, rcfg, psteps)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: croom
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: chroot-based linux sandbox cli
|
|
5
|
+
Project-URL: Homepage, https://github.com/juanvel4000/croom
|
|
6
|
+
Project-URL: Repository, https://github.com/juanvel4000/croom
|
|
7
|
+
Project-URL: Issues, https://github.com/juanvel4000/croom/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/juanvel4000/croom/blob/main/CHANGELOG.md
|
|
9
|
+
Author: juanvel400
|
|
10
|
+
License-Expression: BSD-3-Clause
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: chroot,cli,sandbox
|
|
13
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: System Administrators
|
|
16
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
25
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# croom
|
|
29
|
+
|
|
30
|
+
[](https://github.com/juanvel4000/croom/actions/workflows/tests.yml)
|
|
31
|
+
[](https://github.com/juanvel4000/croom/actions/workflows/publish.yml)
|
|
32
|
+
|
|
33
|
+
a simple Linux sandbox CLI.
|
|
34
|
+
|
|
35
|
+
## overview
|
|
36
|
+
|
|
37
|
+
croom provides a simpler way to create and interact with semi-isolated environments ("`Rooms`"). it uses utilities such as `unshare` and standard Unix tools to construct and provide these environments without root privileges.
|
|
38
|
+
|
|
39
|
+
croom environments are not designed to provide security isolation. instead, they provide a simple space to try, run, and test programs in custom, semi-isolated environments.
|
|
40
|
+
|
|
41
|
+
> croom uses `croom` as the project wide name and `croom` as the distribution name.
|
|
42
|
+
|
|
43
|
+
## project status
|
|
44
|
+
|
|
45
|
+
croom is in active development. while functional, it is **not yet production-ready** for real-world usage.
|
|
46
|
+
|
|
47
|
+
- [CHANGELOG.md](CHANGELOG.md) -- release history
|
|
48
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md) -- how to report bugs and send patches
|
|
49
|
+
|
|
50
|
+
## license
|
|
51
|
+
|
|
52
|
+
BSD-3-Clause, see [LICENSE](LICENSE)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
croom/__init__.py,sha256=uZuhD9s5qXq2lrLkyf6CKrF87C_fkKfNxVeXLmuQ0bA,130
|
|
2
|
+
croom/helpers.py,sha256=jTWDuCXPeYc-40p6FIj79SefuyBWQtjlaI0dBdMbN2Y,204
|
|
3
|
+
croom/room.py,sha256=Hj3Hil3sBUP3kH6CWLABShuF7ank4rW_sV5wqbn62Y8,49
|
|
4
|
+
croom/roomspec.py,sha256=Ng78HYWwfyzQbsRMTnywYh9JyTVo9WzmHSTVbc78A_g,3805
|
|
5
|
+
croom-0.1.0.dist-info/METADATA,sha256=nfCvJnLoaw1-7USRufeKoSicfIqfbKAGYM2oeazDeCg,2229
|
|
6
|
+
croom-0.1.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
7
|
+
croom-0.1.0.dist-info/entry_points.txt,sha256=f9o-tcEh5gS5OCcOoKLimH526qlnhYsoqgR0bQYM32Y,41
|
|
8
|
+
croom-0.1.0.dist-info/licenses/LICENSE,sha256=qioo2eoiY8QhGSbjOXvakhjPzwlmPFxxdFlDT4YIDrU,1471
|
|
9
|
+
croom-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
|
|
2
|
+
Copyright (c) 2026 juanvel400.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
5
|
+
|
|
6
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
7
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
8
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
9
|
+
|
|
10
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|