Setting the file. One moment. Bootstrap IO · Foundry Iq · microsoft/azure-skills · Skills DocsFile Cu Canary
def create_private_directory
— line 286
This file
- Number
- 10.24
- Position
- 24 of 77
- Type
- Python
- Size
- 29 KB
- Lines
- 589
helpers/_bootstrap_io.py
Python·589 lines·29 KB
contextmanager
13from pathlib import Path
14
15try:
16 from ._common import HelperFailure, canonical_bytes
17except ImportError:
18 from _common import HelperFailure, canonical_bytes
19
20MAX_BYTES = 1024 * 1024
21
22
23def failure(code, message):
24 return HelperFailure(code, message, blocked_at="verification")
25
26
27def read_json(path):
28 try:
29 with Path(path).open("rb") as handle:
30 raw = handle.read(MAX_BYTES + 1)
31 if len(raw) > MAX_BYTES:
32 raise failure("bootstrap-input-invalid", "JSON exceeds the one MiB input limit.")
33 value = json.loads(raw.decode("utf-8"))
34 pending = [(value, 0)]
35 count = 0
36 while pending:
37 item, depth = pending.pop()
38 count += 1
39 if depth > 20 or count > 10000:
40 raise ValueError("JSON structure exceeds limits")
41 if isinstance(item, dict):
42 pending.extend((v, depth + 1) for v in item.values())
43 elif isinstance(item, list):
44 pending.extend((v, depth + 1) for v in item)
45 json.dumps(value, ensure_ascii=False, allow_nan=False).encode("utf-8")
46 return value
47 except (OSError, UnicodeError, ValueError, RecursionError) as exc:
48 raise failure("bootstrap-input-invalid", "Select bounded, valid UTF-8 JSON.") from exc
49
50
51def _windows_ancestor_acl(owner_text, entries, current):
52 # Windows volume roots are commonly owned by this fixed OS servicing principal.
53 installer = "S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464"
54 trusted = (current, "OW", "SY", "BA", installer)
55 if owner_text not in tuple("O:" + trustee for trustee in trusted if trustee != "OW"):
56 raise OSError("Ancestor owner can change the access boundary")
57 rights = {
58 "FA": 0x1F01FF, "FR": 0x120089, "FW": 0x120116, "FX": 0x1200A0,
59 "GA": 0x10000000, "GR": 0x80000000, "GW": 0x40000000, "GX": 0x20000000,
60 "SD": 0x10000, "RC": 0x20000, "WD": 0x40000, "WO": 0x80000,
61 "CC": 1, "DC": 2, "LC": 4, "SW": 8, "RP": 16, "WP": 32, "DT": 64,
62 "LO": 128, "CR": 256,
63 }
64 for entry in entries:
65 parts = entry.split(";")
66 if len(parts) != 6 or parts[0] not in ("A", "D") or parts[3] or parts[4]:
67 raise OSError("Unsupported ancestor ACL")
68 if parts[0] == "D" or "IO" in parts[1] or parts[5] in trusted:
69 continue
70 value = parts[2]
71 try:
72 mask = int(value, 16) if value.startswith("0x") else 0
73 if not value.startswith("0x"):
74 if not value or len(value) % 2:
75 raise ValueError("Unsupported rights")
76 for start in range(0, len(value), 2):
77 mask |= rights[value[start:start + 2]]
78 except (KeyError, ValueError) as exc:
79 raise OSError("Unsupported ancestor rights") from exc
80 # Delete-child, delete, write-DACL, write-owner, or generic-all can replace retained paths.
81 if mask & 0x100D0040:
82 raise OSError("Another principal can substitute an ancestor or its children")
83
84
85def _windows_private(path, *, ancestor=False):
86 # Inspect effective trustees, not chmod: Windows chmod does not establish privacy.
87 from ctypes import wintypes as w
88 adv = ctypes.WinDLL("advapi32", use_last_error=True)
89 kernel = ctypes.WinDLL("kernel32", use_last_error=True)
90 pointer = ctypes.c_void_p
91 adv.GetNamedSecurityInfoW.argtypes = [w.LPWSTR, w.DWORD, w.DWORD] + [ctypes.POINTER(pointer)] * 5
92 adv.GetNamedSecurityInfoW.restype = w.DWORD
93 adv.ConvertSecurityDescriptorToStringSecurityDescriptorW.argtypes = [
94 pointer, w.DWORD, w.DWORD, ctypes.POINTER(w.LPWSTR), ctypes.POINTER(w.DWORD),
95 ]
96 adv.ConvertSidToStringSidW.argtypes = [pointer, ctypes.POINTER(w.LPWSTR)]
97 adv.OpenProcessToken.argtypes = [w.HANDLE, w.DWORD, ctypes.POINTER(w.HANDLE)]
98 adv.GetTokenInformation.argtypes = [w.HANDLE, ctypes.c_int, pointer, w.DWORD, ctypes.POINTER(w.DWORD)]
99 kernel.GetCurrentProcess.restype = w.HANDLE
100 kernel.CloseHandle.argtypes = [w.HANDLE]
101 kernel.LocalFree.argtypes = [pointer]
102 descriptor, owner, group, dacl, sacl = (pointer() for _ in range(5))
103 text, sid_text, token, size = w.LPWSTR(), w.LPWSTR(), w.HANDLE(), w.DWORD()
104 try:
105 if adv.GetNamedSecurityInfoW(str(path), 1, 5, ctypes.byref(owner), ctypes.byref(group),
106 ctypes.byref(dacl), ctypes.byref(sacl), ctypes.byref(descriptor)):
107 raise OSError("Cannot inspect private ACL")
108 if not adv.ConvertSecurityDescriptorToStringSecurityDescriptorW(
109 descriptor, 1, 5, ctypes.byref(text), None,
110 ):
111 raise OSError("Cannot inspect security descriptor")
112 if not adv.OpenProcessToken(kernel.GetCurrentProcess(), 8, ctypes.byref(token)):
113 raise OSError("Cannot inspect current owner")
114 adv.GetTokenInformation(token, 1, None, 0, ctypes.byref(size))
115 buffer = ctypes.create_string_buffer(size.value)
116 if not adv.GetTokenInformation(token, 1, buffer, size, ctypes.byref(size)):
117 raise OSError("Cannot inspect current owner")
118 sid = ctypes.cast(buffer, ctypes.POINTER(pointer))[0]
119 if not adv.ConvertSidToStringSidW(sid, ctypes.byref(sid_text)):
120 raise OSError("Cannot inspect current owner")
121 sddl = text.value
122 current = sid_text.value
123 owner_text, separator, acl = sddl.partition("D:")
124 if not separator or not dacl:
125 raise OSError("Owner or DACL is not private")
126 entries = re.findall(r"\(([^()]*)\)", acl)
127 if not entries or re.sub(r"\([^()]*\)", "", acl) not in ("", "P", "AI", "PAI"):
128 raise OSError("Unsupported ACL")
129 if ancestor:
130 _windows_ancestor_acl(owner_text, entries, current)
131 return
132 if owner_text != "O:" + current:
133 raise OSError("Owner is not the operator")
134 for entry in entries:
135 parts = entry.split(";")
136 if len(parts) != 6 or parts[0] != "A" or parts[5] not in (current, "OW", "SY", "BA"):
137 raise OSError("ACL grants access to another principal")
138 finally:
139 if token:
140 kernel.CloseHandle(token)
141 for allocated in (descriptor, text, sid_text):
142 if allocated:
143 kernel.LocalFree(ctypes.cast(allocated, pointer))
144
145
146def _outside_plugin(path):
147 skill = Path(__file__).resolve().parents[1]
148 plugin = skill.parent.parent
149 protected = [skill]
150 if any((plugin / marker / "plugin.json").is_file() for marker in (".plugin", ".claude-plugin", ".cursor-plugin")):
151 protected.append(plugin)
152 if any(root in (path.resolve(), *path.resolve().parents) for root in protected):
153 raise OSError("Receipts must be outside the installed plugin")
154
155
156def _safe_leaf(name):
157 return (isinstance(name, str) and re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_.-]{0,199}", name)
158 and not name.endswith(".")
159 and not re.fullmatch(r"(?i)(?:con|prn|aux|nul|com[1-9]|lpt[1-9])", name.split(".")[0]))
160
161
162def _validated_directory(value):
163 if not isinstance(value, str) or not Path(value).is_absolute():
164 raise failure("bootstrap-receipt-private", "Select an absolute, existing private receipt directory.")
165 path = Path(value)
166 try:
167 for part in (path, *path.parents):
168 info = part.lstat()
169 if part == path:
170 selected = info
171 if stat.S_ISLNK(info.st_mode) or getattr(info, "st_file_attributes", 0) & 0x400:
172 raise OSError("Linked paths are unsupported")
173 _outside_plugin(path)
174 if not stat.S_ISDIR(selected.st_mode):
175 raise OSError("Receipt location must be a directory")
176 if os.name == "nt":
177 _windows_private(path)
178 else:
179 if selected.st_uid != os.getuid() or stat.S_IMODE(selected.st_mode) & 0o077:
180 raise OSError("Directory must be private to its owner")
181 except (OSError, ValueError) as exc:
182 raise failure("bootstrap-receipt-private", "Receipt location must be user-owned and private; no ACLs were changed.") from exc
183 return path, selected
184
185
186def private_directory(value):
187 return _validated_directory(value)[0]
188
189
190@contextmanager
191def _windows_security():
192 """An explicit protected, inheritable owner/SYSTEM/admin DACL, supplied at creation."""
193 from ctypes import wintypes as w
194 adv = ctypes.WinDLL("advapi32", use_last_error=True)
195 kernel = ctypes.WinDLL("kernel32", use_last_error=True)
196 pointer = ctypes.c_void_p
197 class Attributes(ctypes.Structure):
198 _fields_ = [("length", w.DWORD), ("descriptor", pointer), ("inherit", w.BOOL)]
199 adv.OpenProcessToken.argtypes = [w.HANDLE, w.DWORD, ctypes.POINTER(w.HANDLE)]
200 adv.GetTokenInformation.argtypes = [w.HANDLE, ctypes.c_int, pointer, w.DWORD, ctypes.POINTER(w.DWORD)]
201 adv.ConvertSidToStringSidW.argtypes = [pointer, ctypes.POINTER(w.LPWSTR)]
202 adv.ConvertStringSecurityDescriptorToSecurityDescriptorW.argtypes = [
203 w.LPCWSTR, w.DWORD, ctypes.POINTER(pointer), ctypes.POINTER(w.DWORD)]
204 kernel.GetCurrentProcess.restype = w.HANDLE
205 kernel.CloseHandle.argtypes = [w.HANDLE]
206 kernel.LocalFree.argtypes = [pointer]
207 token, size, sid_text, descriptor = w.HANDLE(), w.DWORD(), w.LPWSTR(), pointer()
208 try:
209 if not adv.OpenProcessToken(kernel.GetCurrentProcess(), 8, ctypes.byref(token)):
210 raise OSError("Owner unavailable")
211 adv.GetTokenInformation(token, 1, None, 0, ctypes.byref(size))
212 buffer = ctypes.create_string_buffer(size.value)
213 if not adv.GetTokenInformation(token, 1, buffer, size, ctypes.byref(size)):
214 raise OSError("Owner unavailable")
215 if not adv.ConvertSidToStringSidW(ctypes.cast(buffer, ctypes.POINTER(pointer))[0], ctypes.byref(sid_text)):
216 raise OSError("Owner unavailable")
217 sddl = f"O:{sid_text.value}D:P(A;OICI;FA;;;{sid_text.value})(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)"
218 if not adv.ConvertStringSecurityDescriptorToSecurityDescriptorW(sddl, 1, ctypes.byref(descriptor), None):
219 raise OSError("Private descriptor unavailable")
220 yield Attributes(ctypes.sizeof(Attributes), descriptor, False)
221 finally:
222 if token:
223 kernel.CloseHandle(token)
224 for allocated in (sid_text, descriptor):
225 if allocated:
226 kernel.LocalFree(ctypes.cast(allocated, pointer))
227
228
229@contextmanager
230def _pinned_directory(path, *, private=True):
231 """Pin every ancestor against substitution; POSIX writes remain handle-relative."""
232 handles = []
233 try:
234 if os.name == "nt":
235 from ctypes import wintypes as w
236 kernel = ctypes.WinDLL("kernel32", use_last_error=True)
237 kernel.CreateFileW.argtypes = [w.LPCWSTR, w.DWORD, w.DWORD, ctypes.c_void_p,
238 w.DWORD, w.DWORD, w.HANDLE]
239 kernel.CreateFileW.restype = w.HANDLE
240 kernel.CloseHandle.argtypes = [w.HANDLE]
241 for part in reversed((path, *path.parents)):
242 # No FILE_SHARE_DELETE: an opened ancestor cannot be renamed/replaced.
243 handle = kernel.CreateFileW(str(part), 0x81, 3, None, 3, 0x02200000, None)
244 if handle == ctypes.c_void_p(-1).value:
245 raise OSError("Directory cannot be pinned")
246 handles.append(handle)
247 info = part.lstat()
248 if not stat.S_ISDIR(info.st_mode) or getattr(info, "st_file_attributes", 0) & 0x400:
249 raise OSError("Linked directory")
250 _windows_private(part, ancestor=True)
251 if private:
252 _validated_directory(str(path))
253 yield None
254 else:
255 if not hasattr(os, "O_DIRECTORY") or not hasattr(os, "O_NOFOLLOW"):
256 raise OSError("Handle-relative creation unavailable")
257 for part in reversed((path, *path.parents)):
258 fd = os.open(str(part) if not handles else part.name,
259 os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW,
260 **({"dir_fd": handles[-1]} if handles else {}))
261 handles.append(fd)
262 info = os.fstat(fd)
263 # A foreign writable ancestor can substitute descendants, even if the leaf is 0700.
264 if info.st_uid not in (0, os.getuid()) or stat.S_IMODE(info.st_mode) & 0o022:
265 raise OSError("Unsafe ancestor ownership or write access")
266 if private:
267 _, selected = _validated_directory(str(path))
268 opened = os.fstat(handles[-1])
269 if (selected.st_dev, selected.st_ino) != (opened.st_dev, opened.st_ino):
270 raise OSError("Directory identity changed")
271 yield handles[-1]
272 finally:
273 cleanup_failed = False
274 for handle in reversed(handles):
275 try:
276 if os.name == "nt":
277 cleanup_failed = not kernel.CloseHandle(handle) or cleanup_failed
278 else:
279 os.close(handle)
280 except OSError:
281 cleanup_failed = True
282 if cleanup_failed:
283 raise OSError("Directory handle cleanup failed")
284
285
286def create_private_directory(value):
287 """Create one new leaf, never modify an existing directory or its ancestors."""
288 if not isinstance(value, str) or not Path(value).is_absolute():
289 raise failure("bootstrap-receipt-private", "Select an absolute new private directory.")
290 path = Path(value)
291 try:
292 if not _safe_leaf(path.name):
293 raise OSError("Unsafe directory leaf")
294 _outside_plugin(path)
295 with _pinned_directory(path.parent, private=False) as parent_fd:
296 if os.name == "nt":
297 from ctypes import wintypes as w
298 kernel = ctypes.WinDLL("kernel32", use_last_error=True)
299 kernel.CreateDirectoryW.argtypes = [w.LPCWSTR, ctypes.c_void_p]
300 with _windows_security() as attributes:
301 if not kernel.CreateDirectoryW(str(path), ctypes.byref(attributes)):
302 raise OSError("Private directory creation failed")
303 else:
304 os.mkdir(path.name, 0o700, dir_fd=parent_fd)
305 with _pinned_directory(path):
306 return private_directory(str(path))
307 except (OSError, ValueError, NotImplementedError) as exc:
308 raise failure("bootstrap-receipt-private", "Private leaf creation failed; no existing directory ACLs were changed.") from exc
309
310
311def validate_private_artifact_directory(value):
312 path = private_directory(value)
313 try:
314 with _pinned_directory(path):
315 return private_directory(value)
316 except (OSError, ValueError, NotImplementedError) as exc:
317 raise failure("bootstrap-receipt-private", "Private directory or ancestor stability could not be verified; no ACLs were changed.") from exc
318
319
320def _windows_private_open(path, *, create=True):
321 import msvcrt
322 from ctypes import wintypes as w
323 kernel = ctypes.WinDLL("kernel32", use_last_error=True)
324 kernel.CreateFileW.argtypes = [w.LPCWSTR, w.DWORD, w.DWORD, ctypes.c_void_p,
325 w.DWORD, w.DWORD, w.HANDLE]
326 kernel.CreateFileW.restype = w.HANDLE
327 kernel.CloseHandle.argtypes = [w.HANDLE]
328 if create:
329 with _windows_security() as attributes:
330 handle = kernel.CreateFileW(str(path), 0xC0010000, 1, ctypes.byref(attributes), 1, 0x80200000, None)
331 else:
332 handle = kernel.CreateFileW(str(path), 0x80000000, 1, None, 3, 0x00200000, None)
333 if handle == ctypes.c_void_p(-1).value:
334 raise OSError("Private file creation failed")
335 try:
336 return msvcrt.open_osfhandle(handle, (os.O_RDWR if create else os.O_RDONLY) | os.O_BINARY)
337 except BaseException:
338 kernel.CloseHandle(handle)
339 raise
340
341
342def _windows_publish(fd, destination):
343 import msvcrt
344 from ctypes import wintypes as w
345 kernel = ctypes.WinDLL("kernel32", use_last_error=True)
346 target = str(destination)
347 size = len(target.encode("utf-16-le"))
348 class Rename(ctypes.Structure):
349 _fields_ = [("replace", w.BOOL), ("root", w.HANDLE), ("size", w.DWORD),
350 ("name", w.WCHAR * (size // 2 + 1))]
351 value = Rename(False, None, size, target)
352 kernel.SetFileInformationByHandle.argtypes = [w.HANDLE, ctypes.c_int, ctypes.c_void_p, w.DWORD]
353 # Rename the owned, write-through handle, never reopen a substitutable temporary pathname.
354 if not kernel.SetFileInformationByHandle(msvcrt.get_osfhandle(fd), 3, ctypes.byref(value), ctypes.sizeof(value)):
355 raise OSError("Private artifact publication failed")
356
357
358def _cleanup_owned_temporary(directory, name, owned, *, directory_fd=None, primary=None):
359 path = directory / name if directory_fd is None else name
360 kwargs = {} if directory_fd is None else {"dir_fd": directory_fd}
361 try:
362 current = os.stat(path, follow_symlinks=False, **kwargs)
363 except FileNotFoundError:
364 outcome = "already-absent"
365 except (OSError, NotImplementedError):
366 outcome = "inspection-unavailable; entry left untouched"
367 else:
368 if (current.st_dev, current.st_ino) != (owned.st_dev, owned.st_ino):
369 outcome = "identity-changed; entry left untouched"
370 else:
371 try:
372 os.unlink(path, **kwargs)
373 outcome = "removed"
374 except FileNotFoundError:
375 outcome = "already-absent"
376 except (OSError, NotImplementedError):
377 outcome = "removal-unconfirmed; private temporary may remain"
378 warning = "Private temporary cleanup: " + outcome + "."
379 if primary is not None:
380 primary.warnings.append(warning)
381 elif outcome not in ("removed", "already-absent"):
382 error = failure("bootstrap-receipt-failed", "Private temporary cleanup could not be confirmed; no artifact success is reported.")
383 error.warnings.append(warning)
384 raise error
385 return outcome
386
387
388def atomic_private_file(directory, name, value, *, max_bytes=16 * MAX_BYTES):
389 """Publish complete, verified JSON without replacing any existing filesystem entry."""
390 if not _safe_leaf(name):
391 raise failure("bootstrap-receipt-failed", "Artifact name must be a safe ordinary leaf.")
392 try:
393 data = json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=True,
394 allow_nan=False).encode("utf-8") + b"\n"
395 except (TypeError, ValueError, UnicodeError, RecursionError) as exc:
396 raise failure("bootstrap-receipt-failed", "Artifact must contain valid finite UTF-8 JSON.") from exc
397 if len(data) > max_bytes:
398 raise failure("bootstrap-receipt-failed", "Artifact exceeds its output byte bound.")
399 directory = Path(directory)
400 temporary = ".artifact-" + uuid.uuid4().hex
401 owned = None
402 primary = None
403 verified = False
404 try:
405 with _pinned_directory(directory) as directory_fd:
406 kwargs = {} if directory_fd is None else {"dir_fd": directory_fd}
407 leaf = lambda name: directory / name if directory_fd is None else name
408 try:
409 fd = (_windows_private_open(directory / temporary) if os.name == "nt" else
410 os.open(leaf(temporary), os.O_RDWR | os.O_CREAT | os.O_EXCL |
411 os.O_NOFOLLOW, 0o600, **kwargs))
412 try:
413 handle = os.fdopen(fd, "w+b")
414 except BaseException:
415 os.close(fd)
416 raise
417 with handle:
418 owned = os.fstat(handle.fileno())
419 if os.name == "nt":
420 _windows_private(directory / temporary)
421 handle.write(data)
422 handle.flush()
423 os.fsync(handle.fileno())
424 handle.seek(0)
425 if handle.read() != data or os.fstat(handle.fileno()).st_nlink != 1:
426 raise OSError("Artifact integrity failed")
427 if os.name == "nt":
428 _validated_directory(str(directory))
429 _windows_publish(handle.fileno(), directory / name)
430 published = owned
431 owned = None
432 os.fsync(handle.fileno())
433 # Revalidate before publication; cleanup is restricted to our original inode.
434 if os.name != "nt":
435 current = os.stat(leaf(temporary), follow_symlinks=False, **kwargs)
436 if (current.st_dev, current.st_ino) != (owned.st_dev, owned.st_ino):
437 raise OSError("Artifact identity changed")
438 _validated_directory(str(directory))
439 os.link(temporary, name, src_dir_fd=directory_fd, dst_dir_fd=directory_fd,
440 follow_symlinks=False)
441 for entry in (temporary, name):
442 current = os.stat(entry, dir_fd=directory_fd, follow_symlinks=False)
443 if (current.st_dev, current.st_ino) != (owned.st_dev, owned.st_ino):
444 raise OSError("Artifact changed during publication")
445 os.unlink(temporary, dir_fd=directory_fd)
446 published = owned
447 owned = None
448 os.fsync(directory_fd)
449 fd = (_windows_private_open(directory / name, create=False) if os.name == "nt" else
450 os.open(name, os.O_RDONLY | os.O_NOFOLLOW, dir_fd=directory_fd))
451 try:
452 handle = os.fdopen(fd, "rb")
453 except BaseException:
454 os.close(fd)
455 raise
456 with handle:
457 observed = os.fstat(handle.fileno())
458 if ((observed.st_dev, observed.st_ino) != (published.st_dev, published.st_ino)
459 or not stat.S_ISREG(observed.st_mode) or observed.st_nlink != 1
460 or handle.read(len(data) + 1) != data):
461 raise OSError("Published artifact integrity failed")
462 if os.name == "nt":
463 _windows_private(directory / name)
464 _validated_directory(str(directory))
465 verified = True
466 except HelperFailure as exc:
467 primary = exc
468 raise
469 except (OSError, ValueError, NotImplementedError) as exc:
470 primary = failure("bootstrap-receipt-failed", "Private artifact could not be verified and persisted; no artifact success is reported.")
471 raise primary from exc
472 finally:
473 if owned is not None:
474 try:
475 _cleanup_owned_temporary(directory, temporary, owned,
476 directory_fd=directory_fd, primary=primary)
477 except HelperFailure as exc:
478 primary = exc
479 raise
480 except (OSError, ValueError, NotImplementedError) as exc:
481 if primary is not None:
482 primary.warnings.append("Private directory handle cleanup could not be confirmed.")
483 raise primary from primary.__cause__
484 error = failure("bootstrap-receipt-failed", "Private artifact could not be verified and persisted; no artifact success is reported.")
485 if verified:
486 error.warnings.append("Private directory handle cleanup could not be confirmed.")
487 raise error from exc
488 return directory / name
489
490
491def private_file(directory, name, value):
492 return private_bytes(directory, name, canonical_bytes(value) + b"\n")
493
494
495def private_bytes(directory, name, data):
496 if not _safe_leaf(name):
497 raise failure("bootstrap-receipt-failed", "Receipt name must be a safe, ordinary leaf name.")
498 if not isinstance(data, bytes):
499 raise failure("bootstrap-receipt-failed", "Private content must be bounded bytes.")
500 if len(data) > MAX_BYTES:
501 raise failure("bootstrap-receipt-failed", "Sanitized receipt exceeds its bound.")
502 directory_fd = file_fd = None
503 primary = None
504 try:
505 directory, selected = _validated_directory(str(directory))
506 flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, "O_NOFOLLOW", 0)
507 if os.name == "nt":
508 file_fd = os.open(directory / name, flags, 0o600)
509 else:
510 if not hasattr(os, "O_DIRECTORY") or not hasattr(os, "O_NOFOLLOW"):
511 raise failure("bootstrap-receipt-private", "POSIX handle-relative private creation is unavailable.")
512 directory_fd = os.open(directory, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)
513 opened = os.fstat(directory_fd)
514 if ((opened.st_dev, opened.st_ino) != (selected.st_dev, selected.st_ino)
515 or not stat.S_ISDIR(opened.st_mode) or opened.st_uid != os.getuid()
516 or stat.S_IMODE(opened.st_mode) & 0o077):
517 raise failure("bootstrap-receipt-private", "Opened receipt directory changed identity, ownership or permissions.")
518 file_fd = os.open(name, flags, 0o600, dir_fd=directory_fd)
519 handle = os.fdopen(file_fd, "wb")
520 file_fd = None
521 with handle:
522 handle.write(data)
523 handle.flush()
524 os.fsync(handle.fileno())
525 except HelperFailure as exc:
526 primary = exc
527 raise
528 except (OSError, NotImplementedError) as exc:
529 primary = failure("bootstrap-receipt-failed", "Private receipt could not be persisted; retain the returned ownership handoff.")
530 raise primary from exc
531 finally:
532 cleanup_failed = False
533 for descriptor in (file_fd, directory_fd):
534 if descriptor is not None:
535 try:
536 os.close(descriptor)
537 except OSError:
538 cleanup_failed = True
539 if cleanup_failed:
540 if primary is not None:
541 primary.warnings.append("Receipt descriptor cleanup could not be confirmed.")
542 else:
543 raise failure("bootstrap-receipt-failed", "Receipt descriptor cleanup could not be confirmed.")
544 return directory / name
545
546
547def cli_prefix():
548 executable = shutil.which("az")
549 if executable is None:
550 raise failure("bootstrap-tool-unavailable", "A signed-in Azure CLI installation is required.")
551 if os.name == "nt":
552 if Path(executable).suffix.lower() not in (".cmd", ".bat"):
553 raise failure("bootstrap-tool-unavailable", "Windows requires the supported bundled CLI Python layout.")
554 # Use the installed CLI's own interpreter, never cmd.exe or caller commands.
555 # Azure/azure-cli: build_scripts/windows/scripts/az_msi.cmd (and az_zip.cmd).
556 python = Path(executable).parent.parent / "python.exe"
557 if not python.is_file():
558 raise failure("bootstrap-tool-unavailable", "This Windows CLI layout has no supported bundled Python launcher.")
559 return [str(python), "-IBm", "azure.cli"]
560 return [executable]
561
562
563def run_cli(arguments, timeout):
564 """Capture native CLI output; size validation is post-capture, not a memory bound."""
565 env = dict(os.environ, AZURE_EXTENSION_USE_DYNAMIC_INSTALL="no",
566 AZURE_CORE_COLLECT_TELEMETRY="no", AZURE_CORE_ONLY_SHOW_ERRORS="true",
567 AZURE_CORE_NO_COLOR="true", AZURE_LOGGING_ENABLE_LOG_FILE="false",
568 AZURE_AUTO_UPGRADE_ENABLE="false")
569 try:
570 command = cli_prefix() + arguments + ["--output", "json", "--only-show-errors"]
571 result = subprocess.run(command, stdin=subprocess.DEVNULL, capture_output=True,
572 shell=False, env=env, timeout=timeout, check=False)
573 except subprocess.TimeoutExpired as exc:
574 raise failure("bootstrap-cli-timeout", "Native CLI timed out; remote completion and process-tree cleanup are not established.") from exc
575 except OSError as exc:
576 cause = exc
577 for _ in range(8):
578 if not isinstance(cause, OSError):
579 break
580 cause = cause.__context__
581 if isinstance(cause, subprocess.TimeoutExpired):
582 error = failure("bootstrap-cli-timeout", "Native CLI timed out; remote completion is not established.")
583 error.warnings.append("Standard subprocess cleanup also failed; process state is unknown.")
584 else:
585 error = failure("bootstrap-cli-unavailable", "Native CLI execution failed; process and remote state may be unknown.")
586 raise error from exc
587 if len(result.stdout) > MAX_BYTES or len(result.stderr) > MAX_BYTES:
588 raise failure("bootstrap-cli-output-limit", "Captured CLI output exceeds one MiB per stream; this is not a capture-memory bound.")
589 return result.returncode, result.stdout, result.stderr