4"""Secure lock and metadata boundary for the workspace lifecycle shell."""
6from __future__
import annotations
14from pathlib
import Path
15from typing
import NoReturn
17SAFE_FILE_MODE_MASK = stat.S_IWGRP | stat.S_IWOTH
18EXPECTED_METADATA_FIELDS = {
31INHERIT_DESCRIPTOR =
True
34class GuardError(Exception):
35 """One fail-closed workspace boundary violation."""
38def fail(message: str, cause: BaseException |
None =
None) -> NoReturn:
39 """Raise one consistently constructed boundary error."""
40 error = GuardError(message)
42 raise error
from cause
46def lexical(path: str) -> Path:
47 """Return an absolute normalized path without following symlinks."""
48 if not path
or not path.isascii()
or not path.isprintable():
49 fail(
"path must be printable single-line ASCII")
50 expanded = Path(path).expanduser()
51 return Path(os.path.abspath(expanded))
54def _components(path: Path) -> list[Path]:
55 """Return every absolute component from slash through ``path``."""
57 current = Path(parts[0])
59 for part
in parts[1:]:
61 result.append(current)
65def reject_symlink_components(path: Path) ->
None:
66 """Reject every existing symlink component in an absolute path."""
67 for component
in _components(path):
69 info = component.lstat()
70 except FileNotFoundError:
72 if stat.S_ISLNK(info.st_mode):
73 fail(f
"symlink path component is forbidden: {component}")
76def _contains(parent: Path, child: Path) -> bool:
77 """Return whether ``parent`` is equal to or lexically contains ``child``."""
79 child.relative_to(parent)
85def validate_root(raw_root: str, raw_upstream: str) -> tuple[Path, Path]:
86 """Validate or safely create the narrowly scoped workspace root."""
87 root = lexical(raw_root)
88 upstream = lexical(raw_upstream)
89 home = lexical(str(Path.home()))
90 forbidden = (Path(
"/"), home, upstream)
91 if any(root == item
for item
in forbidden):
92 fail(f
"workspace root is a forbidden broad path: {root}")
93 if _contains(root, home)
or _contains(root, upstream):
94 fail(f
"workspace root may not be an ancestor of HOME or the repository: {root}")
95 reject_symlink_components(root)
96 reject_symlink_components(upstream)
97 if not upstream.is_dir():
98 fail(f
"upstream repository is not a directory: {upstream}")
101 if not parent.is_dir():
102 fail(f
"workspace root parent does not exist: {parent}")
103 root.mkdir(mode=0o700)
105 if not stat.S_ISDIR(info.st_mode)
or stat.S_ISLNK(info.st_mode):
106 fail(f
"workspace root is not a real directory: {root}")
107 if info.st_uid != os.geteuid():
108 fail(f
"workspace root has foreign ownership: {root}")
109 if info.st_mode & SAFE_FILE_MODE_MASK:
110 fail(f
"workspace root is group/world writable: {root}")
111 return root, upstream
114def open_lock(root: Path) -> int:
115 """Open and validate the non-following, non-truncating lifecycle lock."""
116 flags = os.O_CREAT | os.O_RDWR | os.O_CLOEXEC
117 flags |= getattr(os,
"O_NOFOLLOW", 0)
118 path = root /
".workspace.lock"
120 descriptor = os.open(path, flags, 0o600)
121 except OSError
as exc:
122 fail(f
"workspace lock could not be opened safely: {exc}", exc)
124 info = os.fstat(descriptor)
126 stat.S_ISREG(info.st_mode),
127 info.st_uid == os.geteuid(),
129 not bool(info.st_mode & SAFE_FILE_MODE_MASK),
132 fail(
"workspace lock must be a private, singly linked regular file")
133 fcntl.flock(descriptor, fcntl.LOCK_EX)
134 os.set_inheritable(descriptor, INHERIT_DESCRIPTOR)
135 except BaseException:
142def run_locked(root: str, upstream: str, script: str, argv: list[str]) -> int:
143 """Hold the validated lock while one shell lifecycle transaction runs."""
144 validated_root, validated_upstream = validate_root(root, upstream)
145 descriptor = open_lock(validated_root)
146 environment = os.environ.copy()
149 "RA8_WS_ROOT": str(validated_root),
150 "RA8_WS_UPSTREAM": str(validated_upstream),
151 "RA8_WS_LOCKED":
"1",
152 "RA8_WS_LOCK_FD": str(descriptor),
155 bash = Path(
"/bin/bash")
156 if not bash.is_file()
or not os.access(bash, os.X_OK):
157 fail(
"/bin/bash is required for workspace lifecycle transactions")
158 child = subprocess.Popen(
159 [str(bash),
"-p", script, *argv],
161 pass_fds=(descriptor,),
164 def forward(signum: int, _frame: object) ->
None:
165 """Forward termination to the transaction that owns the lock."""
166 if child.poll()
is None:
167 child.send_signal(signum)
169 signals = (signal.SIGHUP, signal.SIGINT, signal.SIGTERM)
170 previous = {sig: signal.signal(sig, forward)
for sig
in signals}
174 for sig, handler
in previous.items():
175 signal.signal(sig, handler)
179def _metadata_fields(path: Path) -> dict[str, str]:
180 """Read one private, regular schema-2 metadata record."""
182 if not stat.S_ISREG(info.st_mode)
or stat.S_ISLNK(info.st_mode):
183 fail(
"metadata is not a regular file")
184 if info.st_uid != os.geteuid()
or info.st_nlink != 1
or info.st_mode & SAFE_FILE_MODE_MASK:
185 fail(
"metadata ownership, links, or mode are unsafe")
186 fields: dict[str, str] = {}
187 for line
in path.read_text(encoding=
"ascii").splitlines():
188 key, separator, value = line.partition(
"=")
189 if not separator
or key
in fields
or not value
or not value.isprintable():
190 fail(
"metadata contains an invalid or duplicate field")
192 if set(fields) != EXPECTED_METADATA_FIELDS
or fields.get(
"schema") !=
"2":
193 fail(
"metadata schema is unsupported")
197def validate_metadata(raw_path: str, raw_root: str, name: str, owner: str) -> int:
198 """Validate deletion authority for one exact metadata record."""
199 path = lexical(raw_path)
200 root = lexical(raw_root)
201 expected = root /
".meta" / name
203 fail(
"metadata path is outside its exact reserved slot")
204 fields = _metadata_fields(path)
205 if fields[
"name"] != name
or fields[
"path"] != str(root / name):
206 fail(
"metadata name/path binding is inconsistent")
207 actual_owner = fields[
"owner"]
208 if owner
not in (
"any", actual_owner):
209 fail(f
"metadata owner is {actual_owner}, expected {owner}")
210 if actual_owner
not in {
"agent",
"work"}:
211 fail(
"metadata owner is unsupported")
212 identifier = name.removeprefix(
"work-")
213 if actual_owner ==
"work":
214 if not name.startswith(
"work-")
or fields[
"branch"] != f
"work/{identifier}":
215 fail(
"work metadata violates reserved name/branch binding")
216 elif name.startswith(
"work-"):
217 fail(
"agent metadata may not occupy a reserved work-* name")
221def main(argv: list[str]) -> int:
222 """Dispatch the private lock wrapper or metadata validator."""
224 if len(argv) >= LOCK_ARGC_MIN
and argv[0] ==
"lock" and argv[4] ==
"--":
225 return run_locked(argv[1], argv[2], argv[3], argv[5:])
226 if len(argv) == METADATA_ARGC
and argv[0] ==
"metadata":
227 return validate_metadata(argv[1], argv[2], argv[3], argv[4])
228 fail(
"invalid workspace guard invocation")
229 except (GuardError, OSError, UnicodeError)
as exc:
230 print(f
"workspace guard: {exc}", file=sys.stderr)
234if __name__ ==
"__main__":
235 raise SystemExit(
main(sys.argv[1:]))
void main(void)
The application entry point Reset_Handler hands control to.