@openclaw/fs-safe 0.15.0 → 0.17.0

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.
Files changed (311) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +36 -7
  3. package/dist/absolute-path.d.ts.map +1 -1
  4. package/dist/absolute-path.js +2 -8
  5. package/dist/advanced.d.ts +3 -0
  6. package/dist/advanced.d.ts.map +1 -1
  7. package/dist/advanced.js +3 -0
  8. package/dist/archive-deadline.d.ts.map +1 -1
  9. package/dist/archive-deadline.js +22 -23
  10. package/dist/archive-kind.d.ts +0 -1
  11. package/dist/archive-kind.d.ts.map +1 -1
  12. package/dist/archive-kind.js +5 -17
  13. package/dist/archive-merge.d.ts +1 -0
  14. package/dist/archive-merge.d.ts.map +1 -1
  15. package/dist/archive-merge.js +4 -4
  16. package/dist/archive-native.d.ts +1 -0
  17. package/dist/archive-native.d.ts.map +1 -1
  18. package/dist/archive-native.js +1 -0
  19. package/dist/archive-options.d.ts +2 -0
  20. package/dist/archive-options.d.ts.map +1 -1
  21. package/dist/archive-parser.wasm +0 -0
  22. package/dist/archive-read.d.ts.map +1 -1
  23. package/dist/archive-read.js +6 -7
  24. package/dist/archive-tar-stream.d.ts +3 -0
  25. package/dist/archive-tar-stream.d.ts.map +1 -1
  26. package/dist/archive-tar-stream.js +56 -37
  27. package/dist/archive-tar-wasm.d.ts +16 -4
  28. package/dist/archive-tar-wasm.d.ts.map +1 -1
  29. package/dist/archive-tar-wasm.js +134 -34
  30. package/dist/archive-zip-count.d.ts.map +1 -1
  31. package/dist/archive-zip-count.js +21 -1
  32. package/dist/archive-zip-directory.d.ts.map +1 -1
  33. package/dist/archive-zip-directory.js +23 -1
  34. package/dist/archive-zip-loader.d.ts +2 -0
  35. package/dist/archive-zip-loader.d.ts.map +1 -1
  36. package/dist/archive-zip-loader.js +7 -0
  37. package/dist/archive-zip-names.d.ts.map +1 -1
  38. package/dist/archive-zip-names.js +7 -2
  39. package/dist/archive.d.ts.map +1 -1
  40. package/dist/archive.js +14 -9
  41. package/dist/byte-view.d.ts +3 -0
  42. package/dist/byte-view.d.ts.map +1 -0
  43. package/dist/byte-view.js +13 -0
  44. package/dist/clone-metadata.d.ts +1 -0
  45. package/dist/clone-metadata.d.ts.map +1 -1
  46. package/dist/clone-metadata.js +6 -2
  47. package/dist/create-directory.d.ts +20 -0
  48. package/dist/create-directory.d.ts.map +1 -0
  49. package/dist/create-directory.js +130 -0
  50. package/dist/create-file-async.d.ts +7 -0
  51. package/dist/create-file-async.d.ts.map +1 -0
  52. package/dist/create-file-async.js +121 -0
  53. package/dist/create-file.d.ts +8 -0
  54. package/dist/create-file.d.ts.map +1 -0
  55. package/dist/create-file.js +190 -0
  56. package/dist/create-owned-file.d.ts +8 -0
  57. package/dist/create-owned-file.d.ts.map +1 -0
  58. package/dist/create-owned-file.js +16 -0
  59. package/dist/create.d.ts +4 -0
  60. package/dist/create.d.ts.map +1 -0
  61. package/dist/create.js +2 -0
  62. package/dist/creation-darwin.d.ts +6 -0
  63. package/dist/creation-darwin.d.ts.map +1 -0
  64. package/dist/creation-darwin.js +70 -0
  65. package/dist/creation-file-state.d.ts +19 -0
  66. package/dist/creation-file-state.d.ts.map +1 -0
  67. package/dist/creation-file-state.js +118 -0
  68. package/dist/creation-path.d.ts +21 -0
  69. package/dist/creation-path.d.ts.map +1 -0
  70. package/dist/creation-path.js +71 -0
  71. package/dist/creation-permissions.d.ts +19 -0
  72. package/dist/creation-permissions.d.ts.map +1 -0
  73. package/dist/creation-permissions.js +125 -0
  74. package/dist/directory-durability.d.ts +7 -7
  75. package/dist/directory-durability.d.ts.map +1 -1
  76. package/dist/directory-durability.js +22 -80
  77. package/dist/directory-guard.d.ts +3 -0
  78. package/dist/directory-guard.d.ts.map +1 -1
  79. package/dist/directory-mode-node.d.ts +2 -0
  80. package/dist/directory-mode-node.d.ts.map +1 -1
  81. package/dist/directory-mode-node.js +8 -0
  82. package/dist/directory-receipt.d.ts +24 -0
  83. package/dist/directory-receipt.d.ts.map +1 -0
  84. package/dist/directory-receipt.js +123 -0
  85. package/dist/file-cleanup.d.ts +20 -0
  86. package/dist/file-cleanup.d.ts.map +1 -0
  87. package/dist/file-cleanup.js +81 -0
  88. package/dist/file-contents.d.ts +6 -0
  89. package/dist/file-contents.d.ts.map +1 -0
  90. package/dist/file-contents.js +40 -0
  91. package/dist/file-hash.d.ts.map +1 -1
  92. package/dist/file-hash.js +16 -4
  93. package/dist/file-lock-sync-root-acquire.d.ts.map +1 -1
  94. package/dist/file-lock-sync-root-acquire.js +3 -0
  95. package/dist/file-lock-sync-root-held.d.ts +1 -2
  96. package/dist/file-lock-sync-root-held.d.ts.map +1 -1
  97. package/dist/file-lock-sync-root-held.js +7 -5
  98. package/dist/file-lock-sync-stale-admission.d.ts.map +1 -1
  99. package/dist/file-lock-sync-stale-admission.js +3 -0
  100. package/dist/file-lock-sync.d.ts.map +1 -1
  101. package/dist/file-lock-sync.js +8 -11
  102. package/dist/file-observation.d.ts +1 -1
  103. package/dist/file-observation.d.ts.map +1 -1
  104. package/dist/file-store-boundary.d.ts +2 -6
  105. package/dist/file-store-boundary.d.ts.map +1 -1
  106. package/dist/file-store-boundary.js +3 -9
  107. package/dist/file-store-sync-write.d.ts.map +1 -1
  108. package/dist/file-store-sync-write.js +2 -5
  109. package/dist/file-store.js +3 -3
  110. package/dist/guarded-mkdir.d.ts +1 -0
  111. package/dist/guarded-mkdir.d.ts.map +1 -1
  112. package/dist/guarded-mkdir.js +27 -19
  113. package/dist/install-path.d.ts.map +1 -1
  114. package/dist/install-path.js +2 -5
  115. package/dist/json-durable-queue-ownership.d.ts.map +1 -1
  116. package/dist/json-durable-queue-ownership.js +2 -6
  117. package/dist/json-durable-queue-paths.d.ts.map +1 -1
  118. package/dist/json-durable-queue-paths.js +2 -24
  119. package/dist/json-durable-queue.d.ts.map +1 -1
  120. package/dist/json-durable-queue.js +10 -9
  121. package/dist/json.d.ts.map +1 -1
  122. package/dist/json.js +32 -75
  123. package/dist/local-roots.d.ts.map +1 -1
  124. package/dist/local-roots.js +19 -21
  125. package/dist/move-path-cleanup.d.ts +5 -19
  126. package/dist/move-path-cleanup.d.ts.map +1 -1
  127. package/dist/move-path-cleanup.js +57 -21
  128. package/dist/move-path.d.ts.map +1 -1
  129. package/dist/move-path.js +63 -40
  130. package/dist/native-binding.d.ts +11 -1
  131. package/dist/native-binding.d.ts.map +1 -1
  132. package/dist/native-fallback-warning.d.ts +4 -0
  133. package/dist/native-fallback-warning.d.ts.map +1 -0
  134. package/dist/native-fallback-warning.js +11 -0
  135. package/dist/native-operations.d.ts +0 -2
  136. package/dist/native-operations.d.ts.map +1 -1
  137. package/dist/native-operations.js +0 -24
  138. package/dist/native-parent-admission.d.ts +2 -0
  139. package/dist/native-parent-admission.d.ts.map +1 -1
  140. package/dist/native-parent-admission.js +3 -2
  141. package/dist/native-pinned-write-windows.d.ts +1 -1
  142. package/dist/native-pinned-write-windows.d.ts.map +1 -1
  143. package/dist/native-pinned-write-windows.js +173 -28
  144. package/dist/native-pinned-write.d.ts.map +1 -1
  145. package/dist/native-pinned-write.js +19 -3
  146. package/dist/native-policy-parent-windows.d.ts.map +1 -1
  147. package/dist/native-policy-parent-windows.js +15 -6
  148. package/dist/native-staged-file.d.ts +5 -3
  149. package/dist/native-staged-file.d.ts.map +1 -1
  150. package/dist/native-staged-file.js +90 -40
  151. package/dist/native.js +2 -2
  152. package/dist/opened-realpath.d.ts.map +1 -1
  153. package/dist/opened-realpath.js +11 -2
  154. package/dist/owner-dacl.d.ts.map +1 -1
  155. package/dist/owner-dacl.js +10 -4
  156. package/dist/path.d.ts.map +1 -1
  157. package/dist/path.js +2 -1
  158. package/dist/permissions.d.ts.map +1 -1
  159. package/dist/permissions.js +3 -17
  160. package/dist/pinned-write-input.d.ts +4 -0
  161. package/dist/pinned-write-input.d.ts.map +1 -0
  162. package/dist/pinned-write-input.js +35 -0
  163. package/dist/pinned-write-mode.d.ts +5 -0
  164. package/dist/pinned-write-mode.d.ts.map +1 -0
  165. package/dist/pinned-write-mode.js +31 -0
  166. package/dist/pinned-write-staged.d.ts +6 -0
  167. package/dist/pinned-write-staged.d.ts.map +1 -0
  168. package/dist/pinned-write-staged.js +186 -0
  169. package/dist/pinned-write-types.d.ts +3 -0
  170. package/dist/pinned-write-types.d.ts.map +1 -1
  171. package/dist/pinned-write.d.ts.map +1 -1
  172. package/dist/pinned-write.js +41 -147
  173. package/dist/private-directory.d.ts.map +1 -1
  174. package/dist/private-directory.js +18 -4
  175. package/dist/private-producer-handoff-sync.d.ts +14 -0
  176. package/dist/private-producer-handoff-sync.d.ts.map +1 -0
  177. package/dist/private-producer-handoff-sync.js +114 -0
  178. package/dist/private-producer-handoff.d.ts +22 -4
  179. package/dist/private-producer-handoff.d.ts.map +1 -1
  180. package/dist/private-producer-handoff.js +140 -77
  181. package/dist/publish-copy-stage.d.ts +2 -1
  182. package/dist/publish-copy-stage.d.ts.map +1 -1
  183. package/dist/publish-copy-stage.js +16 -7
  184. package/dist/publish-file.d.ts +2 -2
  185. package/dist/publish-file.d.ts.map +1 -1
  186. package/dist/publish-file.js +58 -98
  187. package/dist/regular-file.d.ts.map +1 -1
  188. package/dist/regular-file.js +35 -44
  189. package/dist/replace-file-copy-fallback.d.ts.map +1 -1
  190. package/dist/replace-file-copy-fallback.js +28 -26
  191. package/dist/replace-file-copy-source.d.ts.map +1 -1
  192. package/dist/replace-file-copy-source.js +13 -22
  193. package/dist/replace-file-descriptor.d.ts.map +1 -1
  194. package/dist/replace-file-descriptor.js +10 -16
  195. package/dist/replace-file-temp-owner.d.ts +0 -7
  196. package/dist/replace-file-temp-owner.d.ts.map +1 -1
  197. package/dist/replace-file-temp-owner.js +9 -60
  198. package/dist/replace-file.d.ts.map +1 -1
  199. package/dist/replace-file.js +9 -13
  200. package/dist/root-create-input.d.ts +2 -1
  201. package/dist/root-create-input.d.ts.map +1 -1
  202. package/dist/root-create-input.js +13 -4
  203. package/dist/root-directory-creation.d.ts +3 -3
  204. package/dist/root-directory-creation.d.ts.map +1 -1
  205. package/dist/root-directory-creation.js +15 -3
  206. package/dist/root-directory-list.d.ts.map +1 -1
  207. package/dist/root-directory-list.js +20 -3
  208. package/dist/root-file-final-admission.d.ts +1 -1
  209. package/dist/root-file-final-admission.d.ts.map +1 -1
  210. package/dist/root-file-final-admission.js +5 -2
  211. package/dist/root-file.d.ts.map +1 -1
  212. package/dist/root-file.js +3 -2
  213. package/dist/root-impl.d.ts.map +1 -1
  214. package/dist/root-impl.js +78 -27
  215. package/dist/root-move-noreplace.d.ts +2 -0
  216. package/dist/root-move-noreplace.d.ts.map +1 -1
  217. package/dist/root-move-noreplace.js +22 -13
  218. package/dist/root-options.d.ts +12 -4
  219. package/dist/root-options.d.ts.map +1 -1
  220. package/dist/root-path-stat.d.ts.map +1 -1
  221. package/dist/root-path-stat.js +59 -7
  222. package/dist/root-read-admission.d.ts.map +1 -1
  223. package/dist/root-read-admission.js +7 -2
  224. package/dist/root-remove.d.ts.map +1 -1
  225. package/dist/root-remove.js +15 -1
  226. package/dist/root-write-publication.js +1 -1
  227. package/dist/secret-file.d.ts.map +1 -1
  228. package/dist/secret-file.js +1 -0
  229. package/dist/secure-file-windows.d.ts +6 -0
  230. package/dist/secure-file-windows.d.ts.map +1 -1
  231. package/dist/secure-file-windows.js +34 -117
  232. package/dist/secure-file.js +2 -2
  233. package/dist/sidecar-lock-acquire.d.ts.map +1 -1
  234. package/dist/sidecar-lock-acquire.js +4 -6
  235. package/dist/sidecar-lock-handle.d.ts +3 -0
  236. package/dist/sidecar-lock-handle.d.ts.map +1 -1
  237. package/dist/sidecar-lock-handle.js +6 -0
  238. package/dist/sidecar-lock-reclaim.d.ts +1 -1
  239. package/dist/sidecar-lock-reclaim.d.ts.map +1 -1
  240. package/dist/sidecar-lock-reclaim.js +11 -8
  241. package/dist/sidecar-lock-root.d.ts.map +1 -1
  242. package/dist/sidecar-lock-root.js +2 -1
  243. package/dist/sidecar-lock.d.ts.map +1 -1
  244. package/dist/sidecar-lock.js +3 -5
  245. package/dist/staged-directory.d.ts +2 -2
  246. package/dist/staged-directory.d.ts.map +1 -1
  247. package/dist/staged-directory.js +6 -6
  248. package/dist/staged-file-settlement.d.ts +17 -0
  249. package/dist/staged-file-settlement.d.ts.map +1 -0
  250. package/dist/staged-file-settlement.js +57 -0
  251. package/dist/strict-file-identity.d.ts +1 -1
  252. package/dist/strict-file-identity.d.ts.map +1 -1
  253. package/dist/strict-file-identity.js +9 -9
  254. package/dist/symlink-parents.d.ts.map +1 -1
  255. package/dist/symlink-parents.js +2 -27
  256. package/dist/temp-workspace-owner.js +4 -4
  257. package/dist/unicode-path.d.ts.map +1 -1
  258. package/dist/unicode-path.js +3 -0
  259. package/dist/walk.d.ts.map +1 -1
  260. package/dist/walk.js +4 -2
  261. package/dist/windows-owner.d.ts.map +1 -1
  262. package/dist/windows-owner.js +2 -1
  263. package/dist/windows-security-bridge.cs +336 -0
  264. package/dist/windows-security-bridge.ps1 +15 -0
  265. package/dist/windows-security-command.d.ts +26 -0
  266. package/dist/windows-security-command.d.ts.map +1 -0
  267. package/dist/windows-security-command.js +363 -0
  268. package/dist/windows-security-facts.d.ts +6 -0
  269. package/dist/windows-security-facts.d.ts.map +1 -0
  270. package/dist/windows-security-facts.js +108 -0
  271. package/dist/write-file-handle.d.ts +7 -0
  272. package/dist/write-file-handle.d.ts.map +1 -1
  273. package/dist/write-file-handle.js +23 -0
  274. package/dist/write-open-flags.d.ts.map +1 -1
  275. package/dist/write-open-flags.js +1 -8
  276. package/dist/write-queue.d.ts.map +1 -1
  277. package/dist/write-queue.js +1 -4
  278. package/docs/advanced.md +71 -2
  279. package/docs/archive.md +102 -39
  280. package/docs/atomic.md +29 -5
  281. package/docs/config.md +6 -2
  282. package/docs/contributing.md +48 -4
  283. package/docs/copy.md +2 -0
  284. package/docs/creation.md +132 -0
  285. package/docs/durability.md +59 -0
  286. package/docs/file-contents.md +68 -0
  287. package/docs/install.md +31 -7
  288. package/docs/json.md +5 -4
  289. package/docs/local-roots.md +2 -0
  290. package/docs/migrating-to-0.5.md +15 -6
  291. package/docs/migrating-to-0.6.md +9 -4
  292. package/docs/mutation-policy-proof.md +5 -3
  293. package/docs/native-helper.md +22 -9
  294. package/docs/native.md +47 -15
  295. package/docs/path.md +4 -4
  296. package/docs/permissions.md +37 -14
  297. package/docs/public-api.md +5 -0
  298. package/docs/quickstart.md +1 -1
  299. package/docs/reading.md +2 -2
  300. package/docs/regular-file.md +3 -0
  301. package/docs/root.md +43 -0
  302. package/docs/secret-file.md +11 -2
  303. package/docs/secure-file.md +9 -4
  304. package/docs/sidecar-lock.md +14 -5
  305. package/docs/staged-file.md +9 -3
  306. package/docs/store.md +3 -1
  307. package/docs/temp.md +4 -1
  308. package/docs/types.md +18 -2
  309. package/docs/walk.md +7 -0
  310. package/docs/writing.md +80 -7
  311. package/package.json +18 -15
@@ -1 +1 @@
1
- {"version":3,"file":"secure-file-windows.d.ts","sourceRoot":"","sources":["../src/secure-file-windows.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AASlD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AA4BxD,KAAK,aAAa,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC;AAuHtD,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,KAAK,CAAC;CACb,GAAG,eAAe,CA0ClB"}
1
+ {"version":3,"file":"secure-file-windows.d.ts","sourceRoot":"","sources":["../src/secure-file-windows.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAOlD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAOxD,KAAK,aAAa,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC;AA0BtD,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,KAAK,CAAC;CACb,GAAG,eAAe,CAkBlB;AAgCD,sFAAsF;AACtF,wBAAsB,wBAAwB,CAAC,MAAM,EAAE;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,KAAK,CAAC;CACb,GAAG,OAAO,CAAC,eAAe,CAAC,CAiB3B"}
@@ -1,30 +1,12 @@
1
1
  import { FsSafeError } from "./errors.js";
2
2
  import { recordFileObservationFailure } from "./file-observation.js";
3
3
  import { getNativeBinding } from "./native.js";
4
+ import { getFsSafeNativeConfig } from "./native-config.js";
5
+ import { warnNativeFallback } from "./native-fallback-warning.js";
6
+ import { inspectWindowsDescriptorCommand } from "./windows-security-command.js";
7
+ import { validateSecureWindowsSecurityFacts } from "./windows-security-facts.js";
4
8
  const IDENTITY_RE = /^([0-9a-f]{8}):([0-9a-f]{16})$/;
5
- const SID_RE = /^s-\d+-\d+(?:-\d+)+$/;
6
- const OWNER_CLASSES = new Set(["current-user", "system", "administrators", "foreign"]);
7
9
  const TRUSTED_OWNER_CLASSES = new Set(["current-user", "system", "administrators"]);
8
- const SYSTEM_SID = "s-1-5-18";
9
- const ADMINISTRATORS_SID = "s-1-5-32-544";
10
- const WORLD_SIDS = new Set([
11
- "s-1-1-0", "s-1-5-11", "s-1-5-32-545", "s-1-5-7",
12
- "s-1-5-32-546", "s-1-5-4", "s-1-5-2",
13
- ]);
14
- const GENERIC_READ = 0x8000_0000;
15
- const GENERIC_WRITE = 0x4000_0000;
16
- const GENERIC_ALL = 0x1000_0000;
17
- const DELETE_ACCESS = 0x0001_0000;
18
- const WRITE_DAC = 0x0004_0000;
19
- const WRITE_OWNER = 0x0008_0000;
20
- const FILE_READ_DATA = 0x0000_0001;
21
- const FILE_WRITE_DATA = 0x0000_0002;
22
- const FILE_APPEND_DATA = 0x0000_0004;
23
- const FILE_READ_EA = 0x0000_0008;
24
- const FILE_WRITE_EA = 0x0000_0010;
25
- const FILE_DELETE_CHILD = 0x0000_0040;
26
- const FILE_READ_ATTRIBUTES = 0x0000_0080;
27
- const FILE_WRITE_ATTRIBUTES = 0x0000_0100;
28
10
  function permissionUnverified(message, cause) {
29
11
  throw new FsSafeError("permission-unverified", message, cause === undefined ? {} : { cause });
30
12
  }
@@ -36,9 +18,6 @@ function identityMismatch() {
36
18
  function isRecord(value) {
37
19
  return typeof value === "object" && value !== null;
38
20
  }
39
- function isUint32(value) {
40
- return typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 0xffff_ffff;
41
- }
42
21
  function parseIdentity(value) {
43
22
  if (typeof value !== "string")
44
23
  identityMismatch();
@@ -50,95 +29,6 @@ function parseIdentity(value) {
50
29
  ino: BigInt(`0x${match[2]}`),
51
30
  };
52
31
  }
53
- function validateFlags(value) {
54
- if (!isRecord(value))
55
- return false;
56
- const raw = value.raw;
57
- if (!isUint32(raw) || (raw & ~0xdf) !== 0)
58
- return false;
59
- const fields = [
60
- ["objectInherit", 0x01], ["containerInherit", 0x02],
61
- ["noPropagateInherit", 0x04], ["inheritOnly", 0x08], ["inherited", 0x10],
62
- ["successfulAccess", 0x40], ["failedAccess", 0x80],
63
- ];
64
- return fields.every(([field, bit]) => typeof value[field] === "boolean" && value[field] === ((raw & bit) !== 0));
65
- }
66
- function validateAce(value) {
67
- return isRecord(value) && typeof value.sid === "string" && SID_RE.test(value.sid) &&
68
- isUint32(value.mask) && (value.aceType === "allow" || value.aceType === "deny") &&
69
- validateFlags(value.flags);
70
- }
71
- function canRead(mask) {
72
- return (mask & (GENERIC_ALL | GENERIC_READ | FILE_READ_DATA | FILE_READ_EA |
73
- FILE_READ_ATTRIBUTES)) !== 0;
74
- }
75
- function canWrite(mask) {
76
- return (mask & (GENERIC_ALL | GENERIC_WRITE | FILE_WRITE_DATA | FILE_APPEND_DATA |
77
- FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | FILE_DELETE_CHILD | DELETE_ACCESS |
78
- WRITE_DAC | WRITE_OWNER)) !== 0;
79
- }
80
- function expectedOwnerClass(facts) {
81
- if (facts.ownerSid === facts.currentUserSid)
82
- return "current-user";
83
- if (facts.ownerSid === SYSTEM_SID)
84
- return "system";
85
- if (facts.ownerSid === ADMINISTRATORS_SID)
86
- return "administrators";
87
- return "foreign";
88
- }
89
- function validateSecurity(value) {
90
- if (!isRecord(value))
91
- permissionUnverified("Windows descriptor ACL facts were malformed");
92
- const facts = value;
93
- const booleans = [
94
- "worldWritable", "groupWritable", "worldReadable", "groupReadable",
95
- "fallbackRequired", "daclPresent", "isLocal", "aceListComplete",
96
- ];
97
- if (!booleans.every((field) => typeof facts[field] === "boolean") ||
98
- typeof facts.ownerSid !== "string" || !SID_RE.test(facts.ownerSid) ||
99
- typeof facts.currentUserSid !== "string" || !SID_RE.test(facts.currentUserSid) ||
100
- typeof facts.ownerClass !== "string" || !OWNER_CLASSES.has(facts.ownerClass) ||
101
- !Array.isArray(facts.unsupportedAceTypes) ||
102
- !facts.unsupportedAceTypes.every(isUint32) ||
103
- !Array.isArray(facts.aces) || !facts.aces.every(validateAce)) {
104
- permissionUnverified("Windows descriptor ACL facts were malformed");
105
- }
106
- if (facts.ownerClass !== expectedOwnerClass(facts)) {
107
- permissionUnverified("Windows descriptor owner facts were inconsistent");
108
- }
109
- if (facts.fallbackRequired || !facts.isLocal || !facts.aceListComplete ||
110
- facts.unsupportedAceTypes.length !== 0) {
111
- permissionUnverified("Windows descriptor ACL facts were incomplete or unsupported");
112
- }
113
- if (!facts.daclPresent && facts.aces.length !== 0) {
114
- permissionUnverified("Windows descriptor DACL facts were inconsistent");
115
- }
116
- return facts;
117
- }
118
- function validatePermissionSummary(facts) {
119
- let worldReadable = !facts.daclPresent;
120
- let worldWritable = !facts.daclPresent;
121
- let groupReadable = false;
122
- let groupWritable = false;
123
- const trustedSids = new Set([facts.currentUserSid, SYSTEM_SID, ADMINISTRATORS_SID]);
124
- for (const ace of facts.aces) {
125
- if (ace.aceType !== "allow" || ace.flags.inheritOnly || trustedSids.has(ace.sid))
126
- continue;
127
- const world = WORLD_SIDS.has(ace.sid);
128
- if (world) {
129
- worldReadable ||= canRead(ace.mask);
130
- worldWritable ||= canWrite(ace.mask);
131
- }
132
- else {
133
- groupReadable ||= canRead(ace.mask);
134
- groupWritable ||= canWrite(ace.mask);
135
- }
136
- }
137
- if (facts.worldReadable !== worldReadable || facts.worldWritable !== worldWritable ||
138
- facts.groupReadable !== groupReadable || facts.groupWritable !== groupWritable) {
139
- permissionUnverified("Windows descriptor ACL summary was inconsistent");
140
- }
141
- }
142
32
  export function inspectSecureWindowsDescriptor(params) {
143
33
  let native;
144
34
  try {
@@ -158,14 +48,16 @@ export function inspectSecureWindowsDescriptor(params) {
158
48
  catch (cause) {
159
49
  permissionUnverified("Windows descriptor ACL verification failed", cause);
160
50
  }
51
+ return inspectDescriptorResult(params, result, "native");
52
+ }
53
+ function inspectDescriptorResult(params, result, mechanism) {
161
54
  if (!isRecord(result))
162
55
  permissionUnverified("Windows descriptor ACL facts were malformed");
163
56
  const observed = parseIdentity(result.identity);
164
57
  if (observed.dev !== params.identity.dev || observed.ino !== params.identity.ino) {
165
58
  identityMismatch();
166
59
  }
167
- const facts = validateSecurity(result.security);
168
- validatePermissionSummary(facts);
60
+ const facts = validateSecureWindowsSecurityFacts(result.security);
169
61
  return {
170
62
  ok: true,
171
63
  isSymlink: false,
@@ -179,8 +71,33 @@ export function inspectSecureWindowsDescriptor(params) {
179
71
  groupReadable: facts.groupReadable,
180
72
  ownerSid: facts.ownerSid,
181
73
  ownerTrusted: TRUSTED_OWNER_CLASSES.has(facts.ownerClass),
182
- aclSummary: `native descriptor owner=${facts.ownerClass} world=` +
74
+ aclSummary: `${mechanism} descriptor owner=${facts.ownerClass} world=` +
183
75
  `${facts.worldReadable ? "r" : "-"}${facts.worldWritable ? "w" : "-"} ` +
184
76
  `group=${facts.groupReadable ? "r" : "-"}${facts.groupWritable ? "w" : "-"}`,
185
77
  };
186
78
  }
79
+ /** Both mechanisms inspect the same borrowed handle; the caller owns its lifetime. */
80
+ export async function inspectSecureWindowsFile(params) {
81
+ let native;
82
+ try {
83
+ native = getNativeBinding();
84
+ }
85
+ catch (cause) {
86
+ permissionUnverified("Windows descriptor ACL verification requires the matching native helper", cause);
87
+ }
88
+ if (typeof native?.inspectWindowsSecureFileHandle === "function") {
89
+ return inspectSecureWindowsDescriptor(params);
90
+ }
91
+ if (getFsSafeNativeConfig().mode === "require") {
92
+ permissionUnverified("Windows descriptor ACL verification requires an up-to-date native helper");
93
+ }
94
+ warnNativeFallback("windows-secure-file", "Windows descriptor ACL inspection uses a slower built-in system command.");
95
+ let result;
96
+ try {
97
+ result = await inspectWindowsDescriptorCommand(params.fd);
98
+ }
99
+ catch (cause) {
100
+ permissionUnverified("Windows descriptor ACL verification failed", cause);
101
+ }
102
+ return inspectDescriptorResult(params, result, "system-command");
103
+ }
@@ -13,7 +13,7 @@ import { resolveReadOpenFlags } from "./read-open-flags.js";
13
13
  import { realpathSync } from "./realpath.js";
14
14
  import { inspectPathPermissions, isGroupReadable, isGroupWritable, isWorldReadable, isWorldWritable, modeBits, } from "./permissions.js";
15
15
  import { inspectFileIdentity } from "./strict-file-identity.js";
16
- import { inspectSecureWindowsDescriptor } from "./secure-file-windows.js";
16
+ import { inspectSecureWindowsFile } from "./secure-file-windows.js";
17
17
  import { scheduleTimeout } from "./timing.js";
18
18
  import { anchorWindowsDriveRelativePath, assertNoWindowsPathAlias, resolvePathPreservingWindowsRoot, } from "./windows-path-alias.js";
19
19
  function snapshotTrustedDirs(dirs) {
@@ -209,7 +209,7 @@ async function assertSecurePermissions(options, stat, realPath, identity, fd) {
209
209
  const platform = options.inject?.platform ?? process.platform;
210
210
  const permissions = platform === "win32"
211
211
  ? process.platform === "win32"
212
- ? inspectSecureWindowsDescriptor({ fd, identity, stat })
212
+ ? await inspectSecureWindowsFile({ fd, identity, stat })
213
213
  : await inspectPathPermissions(realPath, options.inject)
214
214
  : inspectOpenedPermissions(stat, platform);
215
215
  const reason = permissions.error ? `: ${formatPermissionErrorDetail(permissions.error)}` : "";
@@ -1 +1 @@
1
- {"version":3,"file":"sidecar-lock-acquire.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-acquire.ts"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAM5F,OAAO,EAA4C,KAAK,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAM3H,YAAY,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAEnE,wBAAsB,kBAAkB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/E,OAAO,EAAE,yBAAyB,CAAC,QAAQ,CAAC,EAC5C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,iBAAiB,CAAC,CA0b5B"}
1
+ {"version":3,"file":"sidecar-lock-acquire.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-acquire.ts"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAM5F,OAAO,EAA4C,KAAK,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAO3H,YAAY,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAEnE,wBAAsB,kBAAkB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/E,OAAO,EAAE,yBAAyB,CAAC,QAAQ,CAAC,EAC5C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,iBAAiB,CAAC,CAsb5B"}
@@ -15,6 +15,7 @@ import { resolveSidecarLockPaths } from "./sidecar-lock-target.js";
15
15
  import { createSuppressedError } from "./suppressed-error.js";
16
16
  import { sleep } from "./timing.js";
17
17
  import { sidecarExclusiveCreate } from "./root-create-input.js";
18
+ import { stopSidecarLockMonitoring } from "./sidecar-lock-handle.js";
18
19
  export async function acquireSidecarLock(options, context) {
19
20
  const admissionAncestry = captureSidecarAdmissionAncestry();
20
21
  const retainOnExit = options.retainOnExit;
@@ -353,8 +354,7 @@ export async function acquireSidecarLock(options, context) {
353
354
  .catch(() => false)
354
355
  .then((stillHeld) => {
355
356
  if (!stillHeld && candidateHeld.compromiseTimer) {
356
- clearInterval(candidateHeld.compromiseTimer);
357
- candidateHeld.compromiseTimer = undefined;
357
+ stopSidecarLockMonitoring(candidateHeld);
358
358
  Reflect.apply(compromisedCallback, options, [{ lockPath, normalizedTargetPath }]);
359
359
  }
360
360
  })
@@ -376,10 +376,8 @@ export async function acquireSidecarLock(options, context) {
376
376
  }
377
377
  catch (err) {
378
378
  try {
379
- if (createdHeld?.compromiseTimer) {
380
- clearInterval(createdHeld.compromiseTimer);
381
- createdHeld.compromiseTimer = undefined;
382
- }
379
+ if (createdHeld)
380
+ stopSidecarLockMonitoring(createdHeld);
383
381
  if (handle) {
384
382
  const failedSnapshot = createdSnapshot ?? { payload: null };
385
383
  try {
@@ -1,6 +1,9 @@
1
1
  import type { Root } from "./root-impl.js";
2
2
  import { type SidecarLockSnapshot } from "./sidecar-lock-reclaim.js";
3
3
  import type { SidecarLockHandle } from "./sidecar-lock-types.js";
4
+ export declare function stopSidecarLockMonitoring(held: {
5
+ compromiseTimer?: NodeJS.Timeout;
6
+ }): void;
4
7
  export declare function createSidecarLockHandle(params: {
5
8
  lockPath: string;
6
9
  normalizedTargetPath: string;
@@ -1 +1 @@
1
- {"version":3,"file":"sidecar-lock-handle.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-handle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,eAAe,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACxC,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9D,GAAG,iBAAiB,CA2BpB;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE;IAClD,oBAAoB,EAAE,MAAM,CAAC;IAC7B,IAAI,EAAE;QACJ,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,mBAAmB,CAAC;QAC9B,QAAQ,CAAC,EAAE,IAAI,CAAC;QAChB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;KACzC,CAAC;IACF,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9D,GAAG,iBAAiB,CAWpB"}
1
+ {"version":3,"file":"sidecar-lock-handle.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-handle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAAE,eAAe,CAAC,EAAE,MAAM,CAAC,OAAO,CAAA;CAAE,GAAG,IAAI,CAI1F;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,eAAe,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACxC,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9D,GAAG,iBAAiB,CA2BpB;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE;IAClD,oBAAoB,EAAE,MAAM,CAAC;IAC7B,IAAI,EAAE;QACJ,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,mBAAmB,CAAC;QAC9B,QAAQ,CAAC,EAAE,IAAI,CAAC;QAChB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;KACzC,CAAC;IACF,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9D,GAAG,iBAAiB,CAWpB"}
@@ -1,4 +1,10 @@
1
1
  import { sidecarLockSnapshotStillPresent, } from "./sidecar-lock-reclaim.js";
2
+ export function stopSidecarLockMonitoring(held) {
3
+ const timer = held.compromiseTimer;
4
+ held.compromiseTimer = undefined;
5
+ if (timer)
6
+ clearInterval(timer);
7
+ }
2
8
  export function createSidecarLockHandle(params) {
3
9
  let released = false;
4
10
  let releasePromise;
@@ -39,7 +39,7 @@ export declare function readSidecarLockRawSnapshotSync(lockPath: string, options
39
39
  onOpenFailure?: (error: unknown) => void;
40
40
  }): SidecarLockRawSnapshot | null;
41
41
  export declare function removeSidecarLockIfUnchangedSync(lockPath: string, observed: SidecarLockSnapshot, assertAuthorized?: () => void): boolean;
42
- export declare function sidecarLockSnapshotMatches(current: SidecarLockSnapshot, observed: SidecarLockSnapshot): boolean;
42
+ export declare function sidecarLockSnapshotMatches(current: SidecarLockRawSnapshot | SidecarLockSnapshot, observed: SidecarLockSnapshot): boolean;
43
43
  export declare function removeSidecarLockIfUnchanged(lockPath: string, observed: SidecarLockSnapshot | null, options?: {
44
44
  lockRoot?: Root;
45
45
  parsePayload?: (raw: string) => unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"sidecar-lock-reclaim.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-reclaim.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sidecar-lock-reclaim.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-reclaim.ts"],"names":[],"mappings":"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"}
@@ -71,6 +71,12 @@ function missingSnapshotPath(error) {
71
71
  export async function readSidecarLockSnapshot(lockPath, options = {}) {
72
72
  return parseSidecarLockSnapshot(await readSidecarLockRawSnapshot(lockPath, options), options.parsePayload);
73
73
  }
74
+ async function readSidecarLockComparisonSnapshot(lockPath, options) {
75
+ const snapshot = await readSidecarLockRawSnapshot(lockPath, options);
76
+ const parsePayload = options?.parsePayload;
77
+ // Ownership uses raw bytes and identity, but custom parsers retain their effects.
78
+ return parsePayload ? parseSidecarLockSnapshot(snapshot, parsePayload) : snapshot;
79
+ }
74
80
  export async function readSidecarLockRawSnapshot(lockPath, options = {}) {
75
81
  let handle;
76
82
  try {
@@ -197,7 +203,6 @@ export function readSidecarLockRawSnapshotSync(lockPath, options = {}) {
197
203
  return {
198
204
  raw,
199
205
  stat: after,
200
- ownershipToken: readSidecarLockOwnershipToken(raw),
201
206
  };
202
207
  }
203
208
  finally {
@@ -207,7 +212,7 @@ export function readSidecarLockRawSnapshotSync(lockPath, options = {}) {
207
212
  }
208
213
  export function removeSidecarLockIfUnchangedSync(lockPath, observed, assertAuthorized) {
209
214
  assertAuthorized?.();
210
- const current = readSidecarLockSnapshotSync(lockPath);
215
+ const current = readSidecarLockRawSnapshotSync(lockPath);
211
216
  assertAuthorized?.();
212
217
  if (!current || !sidecarLockSnapshotMatches(current, observed))
213
218
  return false;
@@ -219,10 +224,8 @@ export function sidecarLockSnapshotMatches(current, observed) {
219
224
  if (observed.ownershipToken !== undefined) {
220
225
  return (current.stat?.isFile() === true &&
221
226
  current.raw !== undefined &&
222
- observed.raw !== undefined &&
223
- readSidecarLockOwnershipToken(current.raw) === observed.ownershipToken &&
224
- readSidecarLockOwnershipToken(observed.raw) === observed.ownershipToken &&
225
- current.raw === observed.raw);
227
+ current.raw === observed.raw &&
228
+ readSidecarLockOwnershipToken(current.raw) === observed.ownershipToken);
226
229
  }
227
230
  if (observed.stat &&
228
231
  current.stat &&
@@ -235,7 +238,7 @@ export function sidecarLockSnapshotMatches(current, observed) {
235
238
  return observed.stat !== undefined && current.stat !== undefined;
236
239
  }
237
240
  export async function removeSidecarLockIfUnchanged(lockPath, observed, options = {}) {
238
- const current = await readSidecarLockSnapshot(lockPath, {
241
+ const current = await readSidecarLockComparisonSnapshot(lockPath, {
239
242
  ...options,
240
243
  allowDescriptorIdentityDrift: observed?.ownershipToken !== undefined,
241
244
  });
@@ -251,7 +254,7 @@ export async function removeSidecarLockIfUnchanged(lockPath, observed, options =
251
254
  return true;
252
255
  }
253
256
  export async function sidecarLockSnapshotStillPresent(lockPath, observed, options = {}) {
254
- const current = await readSidecarLockSnapshot(lockPath, {
257
+ const current = await readSidecarLockComparisonSnapshot(lockPath, {
255
258
  ...options,
256
259
  allowDescriptorIdentityDrift: observed?.ownershipToken !== undefined,
257
260
  });
@@ -1 +1 @@
1
- {"version":3,"file":"sidecar-lock-root.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-root.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAGvD,wBAAsB,eAAe,CACnC,QAAQ,EAAE,IAAI,EACd,QAAQ,EAAE,MAAM,EAChB,kBAAkB,CAAC,EAAE,UAAU,GAAG,SAAS,EAC3C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GACvC,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAyD5B"}
1
+ {"version":3,"file":"sidecar-lock-root.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-root.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAGvD,wBAAsB,eAAe,CACnC,QAAQ,EAAE,IAAI,EACd,QAAQ,EAAE,MAAM,EAChB,kBAAkB,CAAC,EAAE,UAAU,GAAG,SAAS,EAC3C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GACvC,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA0D5B"}
@@ -61,7 +61,8 @@ export async function openSidecarRoot(lockRoot, relative, discardObservation, on
61
61
  }
62
62
  catch (probeError) {
63
63
  if (!(probeError instanceof FsSafeError && probeError.code === "not-found") &&
64
- !probe.has(probeError, `stat-leaf-missing:${expectedRealPath}`))
64
+ !probe.has(probeError, `stat-leaf-missing:${expectedRealPath}`) &&
65
+ !probe.has(probeError, `stat-leaf-changed:${expectedRealPath}`))
65
66
  throw probeError;
66
67
  }
67
68
  for (const { dir, stat } of parents)
@@ -1 +1 @@
1
- {"version":3,"file":"sidecar-lock.d.ts","sourceRoot":"","sources":["../src/sidecar-lock.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,yBAAyB,EACzB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAC1E,YAAY,EACV,yBAAyB,EACzB,0BAA0B,EAC1B,iBAAiB,EACjB,oBAAoB,EACpB,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AA2KjC,0FAA0F;AAC1F,wBAAgB,uBAAuB,IAAI,OAAO,CAMjD;AA8HD,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM;cAuB3B,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,WACpD,yBAAyB,CAAC,QAAQ,CAAC,KAC3C,OAAO,CAAC,iBAAiB,CAAC;eAaL,CAAC,EAAE,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,WACxD,yBAAyB,CAAC,QAAQ,CAAC,MACxC,MAAM,OAAO,CAAC,CAAC,CAAC,KACnB,OAAO,CAAC,CAAC,CAAC;iBAqBW,OAAO,CAAC,IAAI,CAAC;iBAQnB,IAAI;uBAIE,oBAAoB,EAAE;EAW/C;AAED,wBAAsB,eAAe,CAAC,CAAC,EAAE,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/E,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,sBAAsB,CAAC,QAAQ,CAAC,EACzC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,CAMZ"}
1
+ {"version":3,"file":"sidecar-lock.d.ts","sourceRoot":"","sources":["../src/sidecar-lock.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,yBAAyB,EACzB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAC1E,YAAY,EACV,yBAAyB,EACzB,0BAA0B,EAC1B,iBAAiB,EACjB,oBAAoB,EACpB,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AA4KjC,0FAA0F;AAC1F,wBAAgB,uBAAuB,IAAI,OAAO,CAMjD;AA2HD,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM;cAuB3B,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,WACpD,yBAAyB,CAAC,QAAQ,CAAC,KAC3C,OAAO,CAAC,iBAAiB,CAAC;eAaL,CAAC,EAAE,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,WACxD,yBAAyB,CAAC,QAAQ,CAAC,MACxC,MAAM,OAAO,CAAC,CAAC,CAAC,KACnB,OAAO,CAAC,CAAC,CAAC;iBAqBW,OAAO,CAAC,IAAI,CAAC;iBAQnB,IAAI;uBAIE,oBAAoB,EAAE;EAW/C;AAED,wBAAsB,eAAe,CAAC,CAAC,EAAE,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/E,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,sBAAsB,CAAC,QAAQ,CAAC,EACzC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,CAMZ"}
@@ -3,7 +3,7 @@ import { FsSafeError } from "./errors.js";
3
3
  import { sameFileIdentity } from "./file-identity.js";
4
4
  import { removeSidecarLockIfUnchanged, sidecarLockSnapshotMatches, } from "./sidecar-lock-reclaim.js";
5
5
  import { acquireSidecarLock } from "./sidecar-lock-acquire.js";
6
- import { createHeldSidecarLockHandle } from "./sidecar-lock-handle.js";
6
+ import { createHeldSidecarLockHandle, stopSidecarLockMonitoring } from "./sidecar-lock-handle.js";
7
7
  import { createSuppressedError } from "./suppressed-error.js";
8
8
  const GLOBAL_STATE_KEY = Symbol.for("fsSafe.sidecarLockManagers");
9
9
  const GLOBAL_CLEANUP_KEY = Symbol.for("fsSafe.sidecarLockCleanupRegistered");
@@ -101,6 +101,7 @@ function releaseAllReclaimGuardsSync(state) {
101
101
  }
102
102
  function releaseAllLocksSync(state, options) {
103
103
  for (const [normalizedTargetPath, held] of state.held) {
104
+ stopSidecarLockMonitoring(held);
104
105
  void held.handle.close().catch(() => undefined);
105
106
  try {
106
107
  const retained = options?.preserveRetained === true && held.retainOnExit;
@@ -257,10 +258,7 @@ async function releaseHeldLock(state, normalizedTargetPath, held, options = {})
257
258
  if (state.held.get(normalizedTargetPath) === held) {
258
259
  state.held.delete(normalizedTargetPath);
259
260
  }
260
- if (held.compromiseTimer) {
261
- clearInterval(held.compromiseTimer);
262
- held.compromiseTimer = undefined;
263
- }
261
+ stopSidecarLockMonitoring(held);
264
262
  })();
265
263
  try {
266
264
  await held.releasePromise;
@@ -1,4 +1,4 @@
1
- import { type BigIntStats } from "node:fs";
1
+ import { type BigIntStats, type Stats } from "node:fs";
2
2
  import type { DirectoryReceipt } from "./directory-durability.js";
3
3
  import type { FileIdentityStat } from "./file-identity.js";
4
4
  import type { NativeBinding } from "./native-binding.js";
@@ -21,7 +21,7 @@ export declare function assertStagedDirectoryCurrent(receipt: StagedDirectorySna
21
21
  export declare function describePolicyStagedDirectory(fd: number, pathname: string, binding?: NativeBinding): PolicyStagedDirectory;
22
22
  export declare function assertPolicyStagedDirectoryCurrent(captured: PolicyStagedDirectory): BigIntStats;
23
23
  export declare function refreshPolicyStagedDirectoryObservation(captured: PolicyStagedDirectory): MutationDirectoryObservation;
24
- export declare function openStagedDirectory(directory: string | DirectoryReceipt): {
24
+ export declare function openStagedDirectory(directory: string | DirectoryReceipt<Stats | BigIntStats>): {
25
25
  fd: number;
26
26
  receipt: StagedDirectorySnapshot;
27
27
  };
@@ -1 +1 @@
1
- {"version":3,"file":"staged-directory.d.ts","sourceRoot":"","sources":["../src/staged-directory.ts"],"names":[],"mappings":"AAAA,OAAW,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,EAEL,KAAK,4BAA4B,EACjC,KAAK,yBAAyB,EAE/B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAGhE,MAAM,MAAM,uBAAuB,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;AAErE,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,SAAS,EAAE,uBAAuB,CAAC;IACnC,WAAW,EAAE,4BAA4B,CAAC;IAC1C,IAAI,EAAE,WAAW,CAAC;IAClB,cAAc,CAAC,EAAE,yBAAyB,CAAC;IAC3C,kBAAkB,CAAC,IAAI,IAAI,CAAC;CAC7B,CAAC,CAAC;AAEH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,QAAQ,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7C,OAAO,CAKT;AAED,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,uBAAuB,CAY7F;AAED,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,uBAAuB,GAAG,WAAW,CAS1F;AASD,wBAAgB,6BAA6B,CAC3C,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,aAAa,GACtB,qBAAqB,CA2CvB;AAED,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,qBAAqB,GAC9B,WAAW,CAeb;AAED,wBAAgB,uCAAuC,CACrD,QAAQ,EAAE,qBAAqB,GAC9B,4BAA4B,CAoB9B;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG;IACzE,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,uBAAuB,CAAC;CAClC,CAiCA"}
1
+ {"version":3,"file":"staged-directory.d.ts","sourceRoot":"","sources":["../src/staged-directory.ts"],"names":[],"mappings":"AAAA,OAAW,EAAE,KAAK,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAE3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAGlE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,EAEL,KAAK,4BAA4B,EACjC,KAAK,yBAAyB,EAE/B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAGhE,MAAM,MAAM,uBAAuB,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;AAErE,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,SAAS,EAAE,uBAAuB,CAAC;IACnC,WAAW,EAAE,4BAA4B,CAAC;IAC1C,IAAI,EAAE,WAAW,CAAC;IAClB,cAAc,CAAC,EAAE,yBAAyB,CAAC;IAC3C,kBAAkB,CAAC,IAAI,IAAI,CAAC;CAC7B,CAAC,CAAC;AAEH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,QAAQ,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7C,OAAO,CAKT;AAED,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,uBAAuB,CAY7F;AAED,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,uBAAuB,GAAG,WAAW,CAS1F;AASD,wBAAgB,6BAA6B,CAC3C,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,aAAa,GACtB,qBAAqB,CA2CvB;AAED,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,qBAAqB,GAC9B,WAAW,CAeb;AAED,wBAAgB,uCAAuC,CACrD,QAAQ,EAAE,qBAAqB,GAC9B,4BAA4B,CAoB9B;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG;IAC9F,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,uBAAuB,CAAC;CAClC,CAgCA"}
@@ -1,5 +1,6 @@
1
1
  import fs, {} from "node:fs";
2
2
  import path from "node:path";
3
+ import { directoryReceiptAuthority, ownDirectoryReceipt } from "./directory-receipt.js";
3
4
  import { FsSafeError } from "./errors.js";
4
5
  import { inspectDirectoryIdentitySync } from "./directory-guard.js";
5
6
  import { nativePolicyDirectoryObserver, NativePolicyDirectoryMismatch } from "./native-policy-directory-observation.js";
@@ -116,16 +117,15 @@ export function refreshPolicyStagedDirectoryObservation(captured) {
116
117
  return checkedMutationDirectory(captured.directory.path, canonicalPath, current);
117
118
  }
118
119
  export function openStagedDirectory(directory) {
119
- // Copy supplied facts before any asynchronous work; receipts are not authority.
120
- const pathname = resolvePathPreservingWindowsRoot(typeof directory === "string" ? directory : directory.path);
121
- const expected = typeof directory === "string" ? undefined : {
122
- realPath: directory.realPath, dev: directory.identity.dev, ino: directory.identity.ino,
123
- };
120
+ const expected = typeof directory === "string"
121
+ ? undefined
122
+ : directoryReceiptAuthority(ownDirectoryReceipt(directory));
123
+ const pathname = resolvePathPreservingWindowsRoot(typeof directory === "string" ? directory : expected.path);
124
124
  const before = fs.lstatSync(pathname, { bigint: true });
125
125
  if (!before.isDirectory()) {
126
126
  throw new FsSafeError("not-file", "staging parent must be a real directory");
127
127
  }
128
- if (expected && (!exactIdentityMatches(expected, before) || realpathSync(pathname) !== expected.realPath)) {
128
+ if (expected && (!exactIdentityMatches(expected.identity, before) || realpathSync(pathname) !== expected.realPath)) {
129
129
  throw new FsSafeError("path-mismatch", "stale staging directory receipt");
130
130
  }
131
131
  const fd = fs.openSync(pathname, fs.constants.O_RDONLY | fs.constants.O_DIRECTORY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
@@ -0,0 +1,17 @@
1
+ import type { BigIntStats } from "node:fs";
2
+ import { FsSafeError } from "./errors.js";
3
+ import type { StagedFileCleanupReceipt, StagedFileFailureDetails, StagedFilePublication, StagedFileReceipt } from "./staged-file-types.js";
4
+ export declare function createStagedFileReceipt(directory: StagedFileReceipt["directory"], temporaryBasename: string, stat: BigIntStats): StagedFileReceipt;
5
+ export declare function stagedFileFailure(error: unknown, details: StagedFileFailureDetails): FsSafeError;
6
+ /** Finish owned cleanup and every close before surfacing publication evidence. */
7
+ export declare function settleStagedFile(params: {
8
+ temporaryBasename: string;
9
+ publication: StagedFilePublication;
10
+ phase: StagedFileFailureDetails["phase"];
11
+ failure?: {
12
+ error: unknown;
13
+ };
14
+ cleanup: () => Promise<StagedFileCleanupReceipt["status"]>;
15
+ close: readonly (() => Promise<void> | void)[];
16
+ }): Promise<void>;
17
+ //# sourceMappingURL=staged-file-settlement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staged-file-settlement.d.ts","sourceRoot":"","sources":["../src/staged-file-settlement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EACV,wBAAwB,EACxB,wBAAwB,EACxB,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAEhC,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,iBAAiB,CAAC,WAAW,CAAC,EACzC,iBAAiB,EAAE,MAAM,EACzB,IAAI,EAAE,WAAW,GAChB,iBAAiB,CAUnB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,wBAAwB,GAAG,WAAW,CAKhG;AAED,kFAAkF;AAClF,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,qBAAqB,CAAC;IACnC,KAAK,EAAE,wBAAwB,CAAC,OAAO,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAC7B,OAAO,EAAE,MAAM,OAAO,CAAC,wBAAwB,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC3D,KAAK,EAAE,SAAS,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;CAChD,GAAG,OAAO,CAAC,IAAI,CAAC,CAkChB"}
@@ -0,0 +1,57 @@
1
+ import { FsSafeError } from "./errors.js";
2
+ export function createStagedFileReceipt(directory, temporaryBasename, stat) {
3
+ return Object.freeze({
4
+ directory,
5
+ temporaryBasename,
6
+ identity: Object.freeze({
7
+ dev: stat.dev, ino: stat.ino, mode: Number(stat.mode & 4095n),
8
+ nlink: stat.nlink, size: stat.size, uid: Number(stat.uid), gid: Number(stat.gid),
9
+ mtimeNs: stat.mtimeNs, ctimeNs: stat.ctimeNs,
10
+ }),
11
+ });
12
+ }
13
+ export function stagedFileFailure(error, details) {
14
+ const code = error instanceof FsSafeError
15
+ ? error.code
16
+ : error?.code === "EEXIST" ? "already-exists" : "helper-failed";
17
+ return new FsSafeError(code, `staged file ${details.phase} failed`, { cause: error, details });
18
+ }
19
+ /** Finish owned cleanup and every close before surfacing publication evidence. */
20
+ export async function settleStagedFile(params) {
21
+ const errors = params.failure ? [params.failure.error] : [];
22
+ let status;
23
+ try {
24
+ status = await params.cleanup();
25
+ }
26
+ catch (error) {
27
+ status = "failed";
28
+ errors.push(error);
29
+ }
30
+ let resources = "closed";
31
+ for (const close of params.close) {
32
+ try {
33
+ await close();
34
+ }
35
+ catch (error) {
36
+ resources = "close-failed";
37
+ errors.push(error);
38
+ }
39
+ }
40
+ const incomplete = status === "failed" || status === "preserved" || resources === "close-failed";
41
+ // A settled pre-publication failure retains the producer/authority rejection exactly.
42
+ if (!incomplete && (!params.failure || params.publication.status === "not-published"))
43
+ return;
44
+ const error = errors.length > 1 ? new AggregateError(errors, "staged operation and settlement failed")
45
+ : errors.length === 1 ? errors[0] : new FsSafeError("not-removable", "staged cleanup preserved an unverified entry");
46
+ const cleanup = Object.freeze({
47
+ temporaryBasename: params.temporaryBasename,
48
+ publication: params.publication,
49
+ status,
50
+ resources,
51
+ });
52
+ throw stagedFileFailure(error, {
53
+ phase: params.failure ? params.phase : "cleanup",
54
+ publication: params.publication,
55
+ cleanup,
56
+ });
57
+ }
@@ -1,6 +1,6 @@
1
1
  import type { BigIntStats } from "node:fs";
2
2
  type ExactFileIdentity = Pick<BigIntStats, "dev" | "ino">;
3
3
  export declare function inspectFileIdentity<T extends ExactFileIdentity>(inspect: () => T | Promise<T>, expected?: ExactFileIdentity, platform?: NodeJS.Platform): Promise<T>;
4
- export declare function inspectFileIdentitySync<T extends ExactFileIdentity>(inspect: () => T, expected?: ExactFileIdentity, platform?: NodeJS.Platform): T;
4
+ export declare function inspectFileIdentitySync<T extends ExactFileIdentity>(inspect: () => T, expected?: ExactFileIdentity, platform?: NodeJS.Platform, mismatch?: () => Error): T;
5
5
  export {};
6
6
  //# sourceMappingURL=strict-file-identity.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"strict-file-identity.d.ts","sourceRoot":"","sources":["../src/strict-file-identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAI3C,KAAK,iBAAiB,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC;AA+B1D,wBAAsB,mBAAmB,CAAC,CAAC,SAAS,iBAAiB,EACnE,OAAO,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC7B,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,OAAO,CAAC,CAAC,CAAC,CAOZ;AAED,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,iBAAiB,EACjE,OAAO,EAAE,MAAM,CAAC,EAChB,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,CAAC,CAmCH"}
1
+ {"version":3,"file":"strict-file-identity.d.ts","sourceRoot":"","sources":["../src/strict-file-identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAI3C,KAAK,iBAAiB,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC;AA+B1D,wBAAsB,mBAAmB,CAAC,CAAC,SAAS,iBAAiB,EACnE,OAAO,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC7B,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,OAAO,CAAC,CAAC,CAAC,CAOZ;AAED,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,iBAAiB,EACjE,OAAO,EAAE,MAAM,CAAC,EAChB,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,QAAQ,GAAE,MAAM,KAAwB,GACvC,CAAC,CAmCH"}