mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 02:06:43 +00:00
refactor: centralize bounded file reads in fs-safe (#111104)
* refactor: use fs-safe bounded descriptor reads * build: update fs-safe to 0.4.2 * build: refresh root npm shrinkwrap * fix: satisfy bounded read return paths * fix: update fs-safe integration for latest main * fix: adopt fs-safe overflow compatibility release * build: complete fs-safe lockfile update * build: update fs-safe to 0.4.4 * build: refresh plugin SDK API baseline * test: follow fs-safe bounded read seam
This commit is contained in:
@@ -13,7 +13,7 @@ e5e67ddf3cab38fcbf9220bc3160715897e2709d9a9ff6ff36f1ecc9453c2367 module/agent-c
|
|||||||
30452bae2a689fb75dcb6dba9ef11e5b95f9cbe0c62eb190a0fcb82d0a19ae52 module/agent-core
|
30452bae2a689fb75dcb6dba9ef11e5b95f9cbe0c62eb190a0fcb82d0a19ae52 module/agent-core
|
||||||
74daa746deb548379d3f0d6eac3c4d082df1034c4360cc03bf51fee0f10a2e4d module/agent-harness
|
74daa746deb548379d3f0d6eac3c4d082df1034c4360cc03bf51fee0f10a2e4d module/agent-harness
|
||||||
e09226afd443cee02ed648f032f53bfeb60585617bb523a649995764d3c38da9 module/agent-harness-exec-review-runtime
|
e09226afd443cee02ed648f032f53bfeb60585617bb523a649995764d3c38da9 module/agent-harness-exec-review-runtime
|
||||||
71ac9e3d66263fc973f3ef724b70300d66d79bdf2f61c6e8478fb49790d81a29 module/agent-harness-runtime
|
ca9810b66aff3c8b60278b80d634c9c280322034964c05cb727d84252080aabf module/agent-harness-runtime
|
||||||
ec22d7a039fb58d0b8343ad149322960d3d8ca58b3f4c70f2fa8a099f8186d0c module/agent-harness-task-runtime
|
ec22d7a039fb58d0b8343ad149322960d3d8ca58b3f4c70f2fa8a099f8186d0c module/agent-harness-task-runtime
|
||||||
5f63bf587bf3547d59d0dc5d0dc2fee54745aa6edaab4aa3ae700dba03443edb module/agent-harness-tool-runtime
|
5f63bf587bf3547d59d0dc5d0dc2fee54745aa6edaab4aa3ae700dba03443edb module/agent-harness-tool-runtime
|
||||||
5168648cd946abad8a92822889f13ceacc87ed502314a66190d0b1eb8ebe76ea module/agent-media-payload
|
5168648cd946abad8a92822889f13ceacc87ed502314a66190d0b1eb8ebe76ea module/agent-media-payload
|
||||||
@@ -35,13 +35,13 @@ a5e9215460bc99fb6e6cdd4bc67eb6466a5e99f28279e13d1769599c18dfe0b3 module/approva
|
|||||||
6c81b9122ab0a5c3190700c0a234047274a8d48edddcc8f26d3859b886696068 module/async-lock-runtime
|
6c81b9122ab0a5c3190700c0a234047274a8d48edddcc8f26d3859b886696068 module/async-lock-runtime
|
||||||
ad60ccc4fe9084d47f0477e02d9296bacad32f26d7456e2a84be8d25a53a25c2 module/boolean-param
|
ad60ccc4fe9084d47f0477e02d9296bacad32f26d7456e2a84be8d25a53a25c2 module/boolean-param
|
||||||
333a906d4ad9d3e89102ab7eb9059a7f9c7277328041223ee3b0713442f56a29 module/browser-config
|
333a906d4ad9d3e89102ab7eb9059a7f9c7277328041223ee3b0713442f56a29 module/browser-config
|
||||||
3a048c3733715f98e839f41a3a50c92e16d432e35bd255987424b7edd3711782 module/bundled-channel-config-schema
|
0de3c53c3ba6ff739d4b047b440588ac25fdea3b795e92b37cab90bfd1520a8c module/bundled-channel-config-schema
|
||||||
b6e53fb9c69840d71785325cd9a244809ffd6d3f0dd08ed0cccf816dd993f210 module/channel-actions
|
b6e53fb9c69840d71785325cd9a244809ffd6d3f0dd08ed0cccf816dd993f210 module/channel-actions
|
||||||
fcfd76dbfe818e8e8574a425f340fee935acf53d4484e961f54c3ec760fb15fe module/channel-activity-runtime
|
fcfd76dbfe818e8e8574a425f340fee935acf53d4484e961f54c3ec760fb15fe module/channel-activity-runtime
|
||||||
24c53c9cefacd8c1bec2aa91ba2b01e606f8b8477bc5cb2f99567225a4dcf67c module/channel-config-helpers
|
24c53c9cefacd8c1bec2aa91ba2b01e606f8b8477bc5cb2f99567225a4dcf67c module/channel-config-helpers
|
||||||
a82cc04b1cda7a647850a13c3de552ab638550c7042f887f32bb0ced7227d143 module/channel-config-primitives
|
16dc9d32e8ca3ef78fc63e0fc4b20e6b943633e9572de1a49d24a880b6ffc66c module/channel-config-primitives
|
||||||
929b3f55b60e3885e33644ed3e1757b82349e1beeeede02eda80f7bf7eea4631 module/channel-config-schema
|
5da2caccf30780a4cf86ac710e2ca42cc9576cb1c49291c0929889fec0cc2257 module/channel-config-schema
|
||||||
16e36f0ddc2ce83cd60e1a96cb4838887e7b328c912ccebbdc9a5d45c550bd07 module/channel-config-schema-legacy
|
080d51451ad15a2787eada3dcc04985154cc394058dfbf2194c6560801f3a1c1 module/channel-config-schema-legacy
|
||||||
8740f7cc786a380043e41aaf710ac47931b3587c122bb152d5f0231f98fd5351 module/channel-config-writes
|
8740f7cc786a380043e41aaf710ac47931b3587c122bb152d5f0231f98fd5351 module/channel-config-writes
|
||||||
2dd98659d9600e755f09ef00dd91c36692b8562ed3700461937e94f6cd1e640a module/channel-contract
|
2dd98659d9600e755f09ef00dd91c36692b8562ed3700461937e94f6cd1e640a module/channel-contract
|
||||||
3db1a968e5b8aa97623a48a9ee76393d578d4bb90634fa59f499a2fd87b9da72 module/channel-core
|
3db1a968e5b8aa97623a48a9ee76393d578d4bb90634fa59f499a2fd87b9da72 module/channel-core
|
||||||
@@ -89,13 +89,13 @@ a224ce0381a32ed7a9d2261669c444f7f46701c15bf2f6121e9b057d9910da78 module/command
|
|||||||
eb4c757fe0086c1dbfa4c3f3caf3dcff0d3cab3924c608237f08f740a6ee5f59 module/command-status
|
eb4c757fe0086c1dbfa4c3f3caf3dcff0d3cab3924c608237f08f740a6ee5f59 module/command-status
|
||||||
10f073c8c7c7384843cb89548e01cf66241e23ebabea01ccc1f9ac7e774f563e module/command-status-runtime
|
10f073c8c7c7384843cb89548e01cf66241e23ebabea01ccc1f9ac7e774f563e module/command-status-runtime
|
||||||
d340686cf814326b5a554a32cc5ca324a9e1254a933c4d9d8d1ada5ac7109a10 module/command-surface
|
d340686cf814326b5a554a32cc5ca324a9e1254a933c4d9d8d1ada5ac7109a10 module/command-surface
|
||||||
251197439b471bc18d7470023b75a4b342884d7096217de9c7e8831ad037818f module/compat
|
e26e0f75b43c5bbadd34401b21d8c76406ca0b87cc997be5abd100462d318f1a module/compat
|
||||||
2cf2f7732af5491a14466fc984f833ddce2b0f6a20b1c82796c3ee856e2966ce module/concurrency-runtime
|
2cf2f7732af5491a14466fc984f833ddce2b0f6a20b1c82796c3ee856e2966ce module/concurrency-runtime
|
||||||
a821f9cc4e6f9339399d99e73f58c3b00baf139aa9d85c22d73c89d8be5702d2 module/config-contracts
|
235a9e4d983042c3db156efcab0e333984cbbf13ebdfcc44a3a5ab40cf3edb4f module/config-contracts
|
||||||
20f3f8042de53e4eee61b64de9102c8c202b9299e6a29235647a4729f70145f2 module/config-mutation
|
20f3f8042de53e4eee61b64de9102c8c202b9299e6a29235647a4729f70145f2 module/config-mutation
|
||||||
316949815affe623ac63951a5db580527f02663576dffa084f02768f612c0c1c module/config-runtime
|
316949815affe623ac63951a5db580527f02663576dffa084f02768f612c0c1c module/config-runtime
|
||||||
0415d7b2b042d44990b3c1ffb7e648bd791bcded3128af35d1a02444f24bce91 module/config-schema
|
adb5fa3476c1f6b4e6c6d2d170254ed781949e7b609be1679661003911635de3 module/config-schema
|
||||||
566ad45c5702acbd7606e2473f5a00c0d4f21722fb9056243b43171cfc856e3e module/config-types
|
1531347939d51c528b7230b951da194faafdfc3d8284765e7e9a0373d1ce5ef8 module/config-types
|
||||||
42d15153981cfe3adc1d5f91621434c56f07a9bd48c15ce34742f72dd040c142 module/context-visibility-runtime
|
42d15153981cfe3adc1d5f91621434c56f07a9bd48c15ce34742f72dd040c142 module/context-visibility-runtime
|
||||||
03636897fb99cb73e4d8620c8a0e0d72b4d52fc32bf94f525af2aa88c489c6c2 module/conversation-binding-runtime
|
03636897fb99cb73e4d8620c8a0e0d72b4d52fc32bf94f525af2aa88c489c6c2 module/conversation-binding-runtime
|
||||||
c1ea9510dfda047609a99d5d2cd1f1560f5d469a36e6b695766213d695c25b0f module/conversation-runtime
|
c1ea9510dfda047609a99d5d2cd1f1560f5d469a36e6b695766213d695c25b0f module/conversation-runtime
|
||||||
@@ -111,7 +111,7 @@ f70c93d28053ca2e8353e45e6515ce7acef188097c6117d1545965d0699c8004 module/device-
|
|||||||
371ee1fd78810526745c93c24c4b85562c981676adcc33aaa0c627f5d2d45810 module/direct-dm-guard-policy
|
371ee1fd78810526745c93c24c4b85562c981676adcc33aaa0c627f5d2d45810 module/direct-dm-guard-policy
|
||||||
91278c800e0f87d7111f226e1cfcb6f29552936fec7215b3b69be4da7e2ee8fb module/directory-config-runtime
|
91278c800e0f87d7111f226e1cfcb6f29552936fec7215b3b69be4da7e2ee8fb module/directory-config-runtime
|
||||||
ea81ef06956c1bc0853fa00afbbc2b5a4019116aaf8a436e1b27d06f7a2c9e88 module/directory-runtime
|
ea81ef06956c1bc0853fa00afbbc2b5a4019116aaf8a436e1b27d06f7a2c9e88 module/directory-runtime
|
||||||
eb069b02d837a4657f8230d0efaaf7cdc913a5ba4866d90f44620f1a8d06c3fe module/discord
|
c443b68d232f28b7241e1be10d1604def0d52d99ce3ae1ca8e2be3c6fd8b2d2f module/discord
|
||||||
f41f9b34ab771c894293453bcdf072860c7cd509dd4e0172156634a816b8d727 module/document-extractor
|
f41f9b34ab771c894293453bcdf072860c7cd509dd4e0172156634a816b8d727 module/document-extractor
|
||||||
3ac20ebba52de5a2f18807c0c8ade6e61f59e260a35fc1d077c9dedb9960dabd module/embedding-providers
|
3ac20ebba52de5a2f18807c0c8ade6e61f59e260a35fc1d077c9dedb9960dabd module/embedding-providers
|
||||||
46c05a90b66032d1d7ad08445840a4bf81aa2bd325348f87710ad4538daf38f6 module/error-runtime
|
46c05a90b66032d1d7ad08445840a4bf81aa2bd325348f87710ad4538daf38f6 module/error-runtime
|
||||||
@@ -225,7 +225,7 @@ c543747f32aebde42508e31606db325739f0c54fcc7cf683f68ac941c835f737 module/provide
|
|||||||
096f53f25cde2c3428b6ff042f1687c5a7c1b161a375ba97aefcdf2f1c38887f module/provider-setup
|
096f53f25cde2c3428b6ff042f1687c5a7c1b161a375ba97aefcdf2f1c38887f module/provider-setup
|
||||||
413af0d4597c1bab45e2f1a260b520445a25b9d11abd46a98fdfb74c60ddd601 module/provider-stream
|
413af0d4597c1bab45e2f1a260b520445a25b9d11abd46a98fdfb74c60ddd601 module/provider-stream
|
||||||
ea8bd63655e983dacfd306fe77d0793097166228a2dabd9b7fc8e33252eb359f module/provider-stream-family
|
ea8bd63655e983dacfd306fe77d0793097166228a2dabd9b7fc8e33252eb359f module/provider-stream-family
|
||||||
dc720974ed8d5cfd98fb3bb2958630736883f38317ee4744ce0b4042fa4485d8 module/provider-stream-shared
|
2285e2c23d64af94ff6b9bd6108e854343f1ec55eca6212fc4fd22138253363b module/provider-stream-shared
|
||||||
5a907292055c941ec7420163ea50e8bc90ead816b3c5867d94a23024d3b579e8 module/provider-tools
|
5a907292055c941ec7420163ea50e8bc90ead816b3c5867d94a23024d3b579e8 module/provider-tools
|
||||||
8236935f56423a26aeb7219173c0c8c8c7aacb4a13d0d851f05bdf2d35790cd4 module/provider-transport-runtime
|
8236935f56423a26aeb7219173c0c8c8c7aacb4a13d0d851f05bdf2d35790cd4 module/provider-transport-runtime
|
||||||
009a594b19aa9f0d0c0c28f54968f807cad4b3ee40ec13c685367116d63aafdc module/provider-usage
|
009a594b19aa9f0d0c0c28f54968f807cad4b3ee40ec13c685367116d63aafdc module/provider-usage
|
||||||
@@ -272,7 +272,7 @@ e9c4398b04d04fead0e46ec618589d8f597a0b6087805ab132138e941b76e190 module/sandbox
|
|||||||
596a315d426121c9620b314e3a9a7f523840b46e007d94d0d5e83cdedf789d15 module/security-runtime
|
596a315d426121c9620b314e3a9a7f523840b46e007d94d0d5e83cdedf789d15 module/security-runtime
|
||||||
50beebb77e461deaccdbff038f6a461dff1d5773426322dc6d7991f6e05a7c37 module/self-hosted-provider-setup
|
50beebb77e461deaccdbff038f6a461dff1d5773426322dc6d7991f6e05a7c37 module/self-hosted-provider-setup
|
||||||
250476d121ffa4ed67d497c59d9c7bb1886973e92ebed39325a02609217bade0 module/session-binding-runtime
|
250476d121ffa4ed67d497c59d9c7bb1886973e92ebed39325a02609217bade0 module/session-binding-runtime
|
||||||
2866ff45859edc6a299cd36eaaf0b9ef32181cc6f0370b7e71eb9deddea5989c module/session-catalog
|
e3cfdf7ff5181ecd517bcb965c11f78b8363c8adf9f7f53f18bdbb5e0ceca1a6 module/session-catalog
|
||||||
f07839f5b8929a179857a0b4b89f8448864078cd5972dd53f9a30e50bf55408d module/session-key-runtime
|
f07839f5b8929a179857a0b4b89f8448864078cd5972dd53f9a30e50bf55408d module/session-key-runtime
|
||||||
f59099aa2d536246d4b1297f01bcea66796351a9259debdd45909afeb7a42d86 module/session-store-runtime
|
f59099aa2d536246d4b1297f01bcea66796351a9259debdd45909afeb7a42d86 module/session-store-runtime
|
||||||
b1d0a76337122cb9dbb0c89fbb8bfacc1a88ce689270d3d684019c9a03ce669a module/session-transcript-hit
|
b1d0a76337122cb9dbb0c89fbb8bfacc1a88ce689270d3d684019c9a03ce669a module/session-transcript-hit
|
||||||
@@ -299,7 +299,7 @@ eb9a25321eaa2bbea1721f7d4b8b218bed398379494e09a21a621f264435b39a module/string-
|
|||||||
32f031eb75c887b24b8eaa693cd0aa1a4648dca85eab7bfdfb3d08136861c274 module/system-event-runtime
|
32f031eb75c887b24b8eaa693cd0aa1a4648dca85eab7bfdfb3d08136861c274 module/system-event-runtime
|
||||||
65361dc9a23578787c1ccf98f7df99e443574614e7ce95889f9a295725e12fae module/talk-config-runtime
|
65361dc9a23578787c1ccf98f7df99e443574614e7ce95889f9a295725e12fae module/talk-config-runtime
|
||||||
9efd666b8c2cc8a9abf816751fd9420f3c048d158e48570cae8b7a4cbc52a83f module/target-resolver-runtime
|
9efd666b8c2cc8a9abf816751fd9420f3c048d158e48570cae8b7a4cbc52a83f module/target-resolver-runtime
|
||||||
cb77f0dcdd4f360cbc5efbb657f57f8ed5840e66adc903a23385ba6d42ca0101 module/telegram-account
|
da05dc1506e226fc25285a2963bd8d96dd0e882d6baa24b8073a0c53fef9fc81 module/telegram-account
|
||||||
7729f9f201c08f114925da75ee86a5a8deb6677e5d1b5ee86bc60aacaa01f63b module/telegram-command-config
|
7729f9f201c08f114925da75ee86a5a8deb6677e5d1b5ee86bc60aacaa01f63b module/telegram-command-config
|
||||||
110944726884fca94f38c9c329b5950629438b9a719f4782c4beeade8bd67746 module/temp-path
|
110944726884fca94f38c9c329b5950629438b9a719f4782c4beeade8bd67746 module/temp-path
|
||||||
a65f17db3d04c2ca1b34f9a4ebe8748952bbcb00318b741adbe3f227d2e2de20 module/text-autolink-runtime
|
a65f17db3d04c2ca1b34f9a4ebe8748952bbcb00318b741adbe3f227d2e2de20 module/text-autolink-runtime
|
||||||
|
|||||||
Generated
+5
-5
@@ -23,7 +23,7 @@
|
|||||||
"@mistralai/mistralai": "2.4.0",
|
"@mistralai/mistralai": "2.4.0",
|
||||||
"@modelcontextprotocol/sdk": "1.29.0",
|
"@modelcontextprotocol/sdk": "1.29.0",
|
||||||
"@mozilla/readability": "0.6.0",
|
"@mozilla/readability": "0.6.0",
|
||||||
"@openclaw/fs-safe": "0.4.1",
|
"@openclaw/fs-safe": "0.4.4",
|
||||||
"@openclaw/proxyline": "0.3.3",
|
"@openclaw/proxyline": "0.3.3",
|
||||||
"@silvia-odwyer/photon-node": "0.3.4",
|
"@silvia-odwyer/photon-node": "0.3.4",
|
||||||
"chalk": "5.6.2",
|
"chalk": "5.6.2",
|
||||||
@@ -434,16 +434,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@openclaw/fs-safe": {
|
"node_modules/@openclaw/fs-safe": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/@openclaw/fs-safe/-/fs-safe-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@openclaw/fs-safe/-/fs-safe-0.4.4.tgz",
|
||||||
"integrity": "sha512-hQi+BxO10KdRFlYUot1syC+hTaUnGeQNdqX5kwkKJig8CFq1tKsYJLPm+zkiiGsSKOprPAquQl/txejEhpKPgg==",
|
"integrity": "sha512-QklFGshaQDXl7RFyxPeSN/1moYq/X+SJcmX/nY3oXJO/tzVasL9i1g3m4nJqIfd6qUTJQjeu+41aIqw8+SbUww==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"tar": "7.5.19"
|
"tar": "7.5.20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@openclaw/proxyline": {
|
"node_modules/@openclaw/proxyline": {
|
||||||
|
|||||||
+1
-1
@@ -2055,7 +2055,7 @@
|
|||||||
"@modelcontextprotocol/sdk": "1.29.0",
|
"@modelcontextprotocol/sdk": "1.29.0",
|
||||||
"@mozilla/readability": "0.6.0",
|
"@mozilla/readability": "0.6.0",
|
||||||
"@openclaw/ai": "workspace:*",
|
"@openclaw/ai": "workspace:*",
|
||||||
"@openclaw/fs-safe": "0.4.1",
|
"@openclaw/fs-safe": "0.4.4",
|
||||||
"@openclaw/proxyline": "0.3.3",
|
"@openclaw/proxyline": "0.3.3",
|
||||||
"@silvia-odwyer/photon-node": "0.3.4",
|
"@silvia-odwyer/photon-node": "0.3.4",
|
||||||
"chalk": "5.6.2",
|
"chalk": "5.6.2",
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
diff --git a/dist/pinned-python.js b/dist/pinned-python.js
|
|
||||||
index c6177eaf56295780ef2edba47ca8bee02cdcdbf2..f6f361974d48f8f4abd3f1e47f1fdb10bc3f2f77 100644
|
|
||||||
--- a/dist/pinned-python.js
|
|
||||||
+++ b/dist/pinned-python.js
|
|
||||||
@@ -93,6 +93,12 @@ def write_all(fd, data):
|
|
||||||
if written <= 0:
|
|
||||||
raise OSError(errno.EIO, "short write")
|
|
||||||
view = view[written:]
|
|
||||||
+def fsync_best_effort(fd):
|
|
||||||
+ try:
|
|
||||||
+ os.fsync(fd)
|
|
||||||
+ except OSError as error:
|
|
||||||
+ if error.errno != errno.EPERM:
|
|
||||||
+ raise
|
|
||||||
def link_unsupported(exc):
|
|
||||||
unsupported = (errno.EPERM, errno.EOPNOTSUPP, getattr(errno, "ENOTSUP", errno.EOPNOTSUPP))
|
|
||||||
return getattr(exc, "errno", None) in unsupported
|
|
||||||
@@ -298,13 +304,13 @@ def write_path(root_fd, payload):
|
|
||||||
temp_name, temp_fd = create_temp_file(parent_fd, basename, mode)
|
|
||||||
os.fchmod(temp_fd, mode)
|
|
||||||
write_all(temp_fd, data)
|
|
||||||
- os.fsync(temp_fd)
|
|
||||||
+ fsync_best_effort(temp_fd)
|
|
||||||
temp_stat = os.fstat(temp_fd)
|
|
||||||
os.close(temp_fd)
|
|
||||||
temp_fd = None
|
|
||||||
result_stat = commit_temp_file(parent_fd, temp_name, basename, overwrite, mode, temp_stat)
|
|
||||||
temp_name = None
|
|
||||||
- os.fsync(parent_fd)
|
|
||||||
+ fsync_best_effort(parent_fd)
|
|
||||||
return {"dev": result_stat.st_dev, "ino": result_stat.st_ino}
|
|
||||||
finally:
|
|
||||||
if temp_fd is not None:
|
|
||||||
diff --git a/dist/pinned-write.js b/dist/pinned-write.js
|
|
||||||
index 77d0ddfa5a1df2de0449c806d19781daaed4910b..09dd77aef95659865b93ce29e15f26e874dd0c25 100644
|
|
||||||
--- a/dist/pinned-write.js
|
|
||||||
+++ b/dist/pinned-write.js
|
|
||||||
@@ -31,6 +31,16 @@ function assertWithinMaxBytes(bytes, maxBytes) {
|
|
||||||
throw new FsSafeError("too-large", `file exceeds limit of ${maxBytes} bytes (got at least ${bytes})`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+async function syncFileBestEffort(handle) {
|
|
||||||
+ try {
|
|
||||||
+ await handle.sync();
|
|
||||||
+ }
|
|
||||||
+ catch (error) {
|
|
||||||
+ if (error?.code !== "EPERM") {
|
|
||||||
+ throw error;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
async function writeStreamToHandle(stream, handle, maxBytes) {
|
|
||||||
let bytes = 0;
|
|
||||||
for await (const chunk of stream) {
|
|
||||||
@@ -192,7 +202,7 @@ async function runPinnedWriteFallback(params) {
|
|
||||||
else {
|
|
||||||
await writeStreamToHandle(params.input.stream, handle, params.maxBytes);
|
|
||||||
}
|
|
||||||
- await handle.sync();
|
|
||||||
+ await syncFileBestEffort(handle);
|
|
||||||
const stat = await handle.stat();
|
|
||||||
await handle.close().catch(() => undefined);
|
|
||||||
await syncDirectoryBestEffort(parentPath);
|
|
||||||
@@ -237,7 +247,7 @@ async function runPinnedWriteFallback(params) {
|
|
||||||
throw new FsSafeError("path-mismatch", "fallback temp path changed during write");
|
|
||||||
}
|
|
||||||
const expectedTempStat = tempStat;
|
|
||||||
- await handle.sync();
|
|
||||||
+ await syncFileBestEffort(handle);
|
|
||||||
await handle.close().catch(() => undefined);
|
|
||||||
handle = undefined;
|
|
||||||
await withAsyncDirectoryGuards([parentGuard], async () => {
|
|
||||||
Generated
+5
-8
@@ -36,9 +36,6 @@ overrides:
|
|||||||
|
|
||||||
packageExtensionsChecksum: sha256-zZ8fyodhMTumshonC7kktCqTPsiHL3UAyS9vltFAlMo=
|
packageExtensionsChecksum: sha256-zZ8fyodhMTumshonC7kktCqTPsiHL3UAyS9vltFAlMo=
|
||||||
|
|
||||||
patchedDependencies:
|
|
||||||
'@openclaw/fs-safe@0.4.1': e49004277fcb3e714125baf15a996682c7310e8e9269c865cc5bcb9fef46a57c
|
|
||||||
|
|
||||||
importers:
|
importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
@@ -86,8 +83,8 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:packages/ai
|
version: link:packages/ai
|
||||||
'@openclaw/fs-safe':
|
'@openclaw/fs-safe':
|
||||||
specifier: 0.4.1
|
specifier: 0.4.4
|
||||||
version: 0.4.1(patch_hash=e49004277fcb3e714125baf15a996682c7310e8e9269c865cc5bcb9fef46a57c)
|
version: 0.4.4
|
||||||
'@openclaw/proxyline':
|
'@openclaw/proxyline':
|
||||||
specifier: 0.3.3
|
specifier: 0.3.3
|
||||||
version: 0.3.3(undici@8.5.0)
|
version: 0.3.3(undici@8.5.0)
|
||||||
@@ -3702,8 +3699,8 @@ packages:
|
|||||||
engines: {node: '>=22'}
|
engines: {node: '>=22'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
'@openclaw/fs-safe@0.4.1':
|
'@openclaw/fs-safe@0.4.4':
|
||||||
resolution: {integrity: sha512-hQi+BxO10KdRFlYUot1syC+hTaUnGeQNdqX5kwkKJig8CFq1tKsYJLPm+zkiiGsSKOprPAquQl/txejEhpKPgg==}
|
resolution: {integrity: sha512-QklFGshaQDXl7RFyxPeSN/1moYq/X+SJcmX/nY3oXJO/tzVasL9i1g3m4nJqIfd6qUTJQjeu+41aIqw8+SbUww==}
|
||||||
engines: {node: '>=22'}
|
engines: {node: '>=22'}
|
||||||
|
|
||||||
'@openclaw/libterminal@0.3.2':
|
'@openclaw/libterminal@0.3.2':
|
||||||
@@ -10072,7 +10069,7 @@ snapshots:
|
|||||||
- bufferutil
|
- bufferutil
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
|
||||||
'@openclaw/fs-safe@0.4.1(patch_hash=e49004277fcb3e714125baf15a996682c7310e8e9269c865cc5bcb9fef46a57c)':
|
'@openclaw/fs-safe@0.4.4':
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
jszip: 3.10.1
|
jszip: 3.10.1
|
||||||
tar: 7.5.19
|
tar: 7.5.19
|
||||||
|
|||||||
+1
-2
@@ -9,7 +9,7 @@ minimumReleaseAge: 2880
|
|||||||
|
|
||||||
minimumReleaseAgeExclude:
|
minimumReleaseAgeExclude:
|
||||||
- "@openclaw/crabline@0.1.11"
|
- "@openclaw/crabline@0.1.11"
|
||||||
- "@openclaw/fs-safe@0.4.1"
|
- "@openclaw/fs-safe@0.4.4"
|
||||||
- "@openclaw/libterminal@0.3.2"
|
- "@openclaw/libterminal@0.3.2"
|
||||||
- "@openclaw/proxyline@0.3.3"
|
- "@openclaw/proxyline@0.3.3"
|
||||||
- "@openclaw/uirouter@0.1.0"
|
- "@openclaw/uirouter@0.1.0"
|
||||||
@@ -155,4 +155,3 @@ packageExtensions:
|
|||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
patchedDependencies:
|
patchedDependencies:
|
||||||
"@openclaw/fs-safe@0.4.1": patches/@openclaw__fs-safe@0.4.1.patch
|
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ import { fileURLToPath } from "node:url";
|
|||||||
import YAML from "yaml";
|
import YAML from "yaml";
|
||||||
|
|
||||||
const ALLOWED_PATCHED_DEPENDENCIES = new Map([
|
const ALLOWED_PATCHED_DEPENDENCIES = new Map([
|
||||||
// Remove after fs-safe ships pinned-write fsync with best-effort EPERM handling.
|
|
||||||
["@openclaw/fs-safe@0.4.1", "patches/@openclaw__fs-safe@0.4.1.patch"],
|
|
||||||
["baileys@7.0.0-rc12", "patches/baileys@7.0.0-rc12.patch"],
|
["baileys@7.0.0-rc12", "patches/baileys@7.0.0-rc12.patch"],
|
||||||
["baileys@7.0.0-rc13", "patches/baileys@7.0.0-rc13.patch"],
|
["baileys@7.0.0-rc13", "patches/baileys@7.0.0-rc13.patch"],
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import path from "node:path";
|
|||||||
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
||||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||||
import { openRootFileSync } from "../infra/boundary-file-read.js";
|
import { openRootFileSync } from "../infra/boundary-file-read.js";
|
||||||
import { readFileDescriptorBoundedSync } from "../infra/file-descriptor-read.js";
|
import { readFileDescriptorBoundedSync } from "../infra/boundary-file-read.js";
|
||||||
import { isRenderableAvatarImageDataUrl } from "../shared/avatar-limits.js";
|
import { isRenderableAvatarImageDataUrl } from "../shared/avatar-limits.js";
|
||||||
import {
|
import {
|
||||||
AVATAR_MAX_BYTES,
|
AVATAR_MAX_BYTES,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { readFileDescriptorBounded } from "../infra/file-descriptor-read.js";
|
import { readFileDescriptorBounded } from "../infra/boundary-file-read.js";
|
||||||
|
|
||||||
// Workspace bootstrap files are model context, not arbitrary attachments. Keep every
|
// Workspace bootstrap files are model context, not arbitrary attachments. Keep every
|
||||||
// read path on the same bound so compaction and sandbox copies cannot bypass it.
|
// read path on the same bound so compaction and sandbox copies cannot bypass it.
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import {
|
|||||||
normalizeStringifiedOptionalString,
|
normalizeStringifiedOptionalString,
|
||||||
} from "@openclaw/normalization-core/string-coerce";
|
} from "@openclaw/normalization-core/string-coerce";
|
||||||
import JSON5 from "json5";
|
import JSON5 from "json5";
|
||||||
|
import { readFileDescriptorBoundedSync } from "../infra/boundary-file-read.js";
|
||||||
import { hasErrnoCode } from "../infra/errors.js";
|
import { hasErrnoCode } from "../infra/errors.js";
|
||||||
import { readFileDescriptorBoundedSync } from "../infra/file-descriptor-read.js";
|
|
||||||
|
|
||||||
export type ConfigSetOptions = {
|
export type ConfigSetOptions = {
|
||||||
strictJson?: boolean;
|
strictJson?: boolean;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { getTerminalTableWidth, renderTable } from "../../packages/terminal-core
|
|||||||
import { isRich, theme } from "../../packages/terminal-core/src/theme.js";
|
import { isRich, theme } from "../../packages/terminal-core/src/theme.js";
|
||||||
import { readBestEffortConfig, type OpenClawConfig } from "../config/config.js";
|
import { readBestEffortConfig, type OpenClawConfig } from "../config/config.js";
|
||||||
import { ADMIN_SCOPE, APPROVALS_SCOPE, type OperatorScope } from "../gateway/method-scopes.js";
|
import { ADMIN_SCOPE, APPROVALS_SCOPE, type OperatorScope } from "../gateway/method-scopes.js";
|
||||||
|
import { readFileDescriptorBounded } from "../infra/boundary-file-read.js";
|
||||||
import { formatErrorMessage } from "../infra/errors.js";
|
import { formatErrorMessage } from "../infra/errors.js";
|
||||||
import {
|
import {
|
||||||
collectExecPolicyScopeSnapshots,
|
collectExecPolicyScopeSnapshots,
|
||||||
@@ -35,7 +36,6 @@ import {
|
|||||||
type ExecApprovalsDefaults,
|
type ExecApprovalsDefaults,
|
||||||
type ExecApprovalsFile,
|
type ExecApprovalsFile,
|
||||||
} from "../infra/exec-approvals.js";
|
} from "../infra/exec-approvals.js";
|
||||||
import { readFileDescriptorBounded } from "../infra/file-descriptor-read.js";
|
|
||||||
import { formatTimeAgo } from "../infra/format-time/format-relative.ts";
|
import { formatTimeAgo } from "../infra/format-time/format-relative.ts";
|
||||||
import { defaultRuntime } from "../runtime.js";
|
import { defaultRuntime } from "../runtime.js";
|
||||||
import { callGatewayFromCli } from "./gateway-rpc.js";
|
import { callGatewayFromCli } from "./gateway-rpc.js";
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ async function readPlanFile(pathname: string): Promise<SecretsApplyPlan> {
|
|||||||
// Apply consumes a generated plan shape, not arbitrary JSON.
|
// Apply consumes a generated plan shape, not arbitrary JSON.
|
||||||
const [fsModule, { readFileDescriptorBounded }, { isSecretsApplyPlan }] = await Promise.all([
|
const [fsModule, { readFileDescriptorBounded }, { isSecretsApplyPlan }] = await Promise.all([
|
||||||
fsModuleLoader.load(),
|
fsModuleLoader.load(),
|
||||||
import("../infra/file-descriptor-read.js"),
|
import("../infra/boundary-file-read.js"),
|
||||||
import("../secrets/plan.js"),
|
import("../secrets/plan.js"),
|
||||||
]);
|
]);
|
||||||
const fsConstants = fsModule.constants as typeof fsModule.constants & { O_NONBLOCK?: number };
|
const fsConstants = fsModule.constants as typeof fsModule.constants & { O_NONBLOCK?: number };
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import {
|
|||||||
import { isGatewaySecretRefUnavailableError } from "../gateway/credentials.js";
|
import { isGatewaySecretRefUnavailableError } from "../gateway/credentials.js";
|
||||||
import { ADMIN_SCOPE } from "../gateway/operator-scopes.js";
|
import { ADMIN_SCOPE } from "../gateway/operator-scopes.js";
|
||||||
import { createAbortError } from "../infra/abort-signal.js";
|
import { createAbortError } from "../infra/abort-signal.js";
|
||||||
import { readFileDescriptorBounded } from "../infra/file-descriptor-read.js";
|
import { readFileDescriptorBounded } from "../infra/boundary-file-read.js";
|
||||||
import { parseStrictNonNegativeInteger } from "../infra/parse-finite-number.js";
|
import { parseStrictNonNegativeInteger } from "../infra/parse-finite-number.js";
|
||||||
import { routeLogsToStderr } from "../logging/console.js";
|
import { routeLogsToStderr } from "../logging/console.js";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ import {
|
|||||||
} from "../agents/identity-avatar.js";
|
} from "../agents/identity-avatar.js";
|
||||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||||
import { matchRootFileOpenFailure, openRootFileSync } from "../infra/boundary-file-read.js";
|
import { matchRootFileOpenFailure, openRootFileSync } from "../infra/boundary-file-read.js";
|
||||||
|
import { readFileDescriptorBounded } from "../infra/boundary-file-read.js";
|
||||||
import {
|
import {
|
||||||
isPackageProvenControlUiRootSync,
|
isPackageProvenControlUiRootSync,
|
||||||
resolveControlUiRootSync,
|
resolveControlUiRootSync,
|
||||||
} from "../infra/control-ui-assets.js";
|
} from "../infra/control-ui-assets.js";
|
||||||
import { resolveDevInstallGitBranch } from "../infra/dev-install-branch.js";
|
import { resolveDevInstallGitBranch } from "../infra/dev-install-branch.js";
|
||||||
import { listDevicePairing, verifyDeviceToken } from "../infra/device-pairing.js";
|
import { listDevicePairing, verifyDeviceToken } from "../infra/device-pairing.js";
|
||||||
import { readFileDescriptorBounded } from "../infra/file-descriptor-read.js";
|
|
||||||
import { openLocalFileSafely, FsSafeError } from "../infra/fs-safe.js";
|
import { openLocalFileSafely, FsSafeError } from "../infra/fs-safe.js";
|
||||||
import { safeFileURLToPath } from "../infra/local-file-access.js";
|
import { safeFileURLToPath } from "../infra/local-file-access.js";
|
||||||
import { verifyPairingToken } from "../infra/pairing-token.js";
|
import { verifyPairingToken } from "../infra/pairing-token.js";
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { normalizeTrimmedStringList } from "@openclaw/normalization-core/string-
|
|||||||
import { MANIFEST_KEY } from "../compat/legacy-names.js";
|
import { MANIFEST_KEY } from "../compat/legacy-names.js";
|
||||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||||
import { openRootFileSync } from "../infra/boundary-file-read.js";
|
import { openRootFileSync } from "../infra/boundary-file-read.js";
|
||||||
import { readFileDescriptorBoundedSync } from "../infra/file-descriptor-read.js";
|
import { readFileDescriptorBoundedSync } from "../infra/boundary-file-read.js";
|
||||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||||
import { isPathInsideWithRealpath } from "../security/scan-paths.js";
|
import { isPathInsideWithRealpath } from "../security/scan-paths.js";
|
||||||
import { CONFIG_DIR, resolveUserPath } from "../utils.js";
|
import { CONFIG_DIR, resolveUserPath } from "../utils.js";
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
// Tests safe boundary file reads against upstream fs-safe behavior.
|
// Tests safe boundary file reads against upstream fs-safe behavior.
|
||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
import * as upstream from "@openclaw/fs-safe/advanced";
|
import * as upstream from "@openclaw/fs-safe/advanced";
|
||||||
import { describe, expect, it } from "vitest";
|
import { afterEach, describe, expect, it } from "vitest";
|
||||||
|
import { useAutoCleanupTempDirTracker } from "../../test/helpers/temp-dir.js";
|
||||||
import * as shim from "./boundary-file-read.js";
|
import * as shim from "./boundary-file-read.js";
|
||||||
|
|
||||||
|
const tempDirs = useAutoCleanupTempDirTracker(afterEach);
|
||||||
|
|
||||||
describe("root file open shim", () => {
|
describe("root file open shim", () => {
|
||||||
it("re-exports the fs-safe root file helpers", () => {
|
it("re-exports the fs-safe root file helpers", () => {
|
||||||
expect(shim.canUseRootFileOpen).toBe(upstream.canUseRootFileOpen);
|
expect(shim.canUseRootFileOpen).toBe(upstream.canUseRootFileOpen);
|
||||||
@@ -10,4 +15,28 @@ describe("root file open shim", () => {
|
|||||||
expect(shim.openRootFile).toBe(upstream.openRootFile);
|
expect(shim.openRootFile).toBe(upstream.openRootFile);
|
||||||
expect(shim.openRootFileSync).toBe(upstream.openRootFileSync);
|
expect(shim.openRootFileSync).toBe(upstream.openRootFileSync);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("preserves the existing overflow error for fs-safe descriptor reads", async () => {
|
||||||
|
const dir = tempDirs.make("openclaw-boundary-file-read-");
|
||||||
|
const filePath = path.join(dir, "oversized.txt");
|
||||||
|
fs.writeFileSync(filePath, "oversized");
|
||||||
|
|
||||||
|
const asyncFd = fs.openSync(filePath, "r");
|
||||||
|
try {
|
||||||
|
await expect(shim.readFileDescriptorBounded(asyncFd, 4)).rejects.toThrow(
|
||||||
|
new RangeError("File exceeds 4 bytes"),
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
fs.closeSync(asyncFd);
|
||||||
|
}
|
||||||
|
|
||||||
|
const syncFd = fs.openSync(filePath, "r");
|
||||||
|
try {
|
||||||
|
expect(() => shim.readFileDescriptorBoundedSync(syncFd, 4)).toThrow(
|
||||||
|
new RangeError("File exceeds 4 bytes"),
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
fs.closeSync(syncFd);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
// Exposes root-scoped file open helpers with fs-safe defaults.
|
// Exposes root-scoped file open helpers with fs-safe defaults.
|
||||||
import "./fs-safe-defaults.js";
|
import "./fs-safe-defaults.js";
|
||||||
|
import {
|
||||||
|
readFileDescriptorBounded as readFileDescriptorBoundedFsSafe,
|
||||||
|
readFileDescriptorBoundedSync as readFileDescriptorBoundedSyncFsSafe,
|
||||||
|
} from "@openclaw/fs-safe/advanced";
|
||||||
|
import { FsSafeError } from "@openclaw/fs-safe/errors";
|
||||||
|
|
||||||
// Root-scoped file open helpers. Use these for user paths that must stay under
|
// Root-scoped file open helpers. Use these for user paths that must stay under
|
||||||
// an already trusted boundary.
|
// an already trusted boundary.
|
||||||
@@ -11,3 +16,28 @@ export {
|
|||||||
type RootFileOpenFailure,
|
type RootFileOpenFailure,
|
||||||
type RootFileOpenResult,
|
type RootFileOpenResult,
|
||||||
} from "@openclaw/fs-safe/advanced";
|
} from "@openclaw/fs-safe/advanced";
|
||||||
|
|
||||||
|
function preserveOpenClawOverflowError(error: unknown, maxBytes: number): never {
|
||||||
|
if (error instanceof FsSafeError && error.code === "too-large") {
|
||||||
|
throw new RangeError(`File exceeds ${maxBytes} bytes`, { cause: error });
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read a pinned descriptor without changing OpenClaw's user-facing overflow error. */
|
||||||
|
export async function readFileDescriptorBounded(fd: number, maxBytes: number): Promise<Buffer> {
|
||||||
|
try {
|
||||||
|
return await readFileDescriptorBoundedFsSafe(fd, maxBytes);
|
||||||
|
} catch (error) {
|
||||||
|
return preserveOpenClawOverflowError(error, maxBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Synchronous variant for callers that own a pinned descriptor. */
|
||||||
|
export function readFileDescriptorBoundedSync(fd: number, maxBytes: number): Buffer {
|
||||||
|
try {
|
||||||
|
return readFileDescriptorBoundedSyncFsSafe(fd, maxBytes);
|
||||||
|
} catch (error) {
|
||||||
|
return preserveOpenClawOverflowError(error, maxBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
// Bounded reads for file descriptors already pinned by a boundary open.
|
|
||||||
import fs from "node:fs";
|
|
||||||
|
|
||||||
const READ_CHUNK_BYTES = 64 * 1024;
|
|
||||||
|
|
||||||
function createScratchBuffer(maxBytes: number): Buffer {
|
|
||||||
return Buffer.allocUnsafe(Math.min(READ_CHUNK_BYTES, Math.max(1, maxBytes + 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
function appendChunk(params: {
|
|
||||||
chunks: Buffer[];
|
|
||||||
scratch: Buffer;
|
|
||||||
bytesRead: number;
|
|
||||||
total: number;
|
|
||||||
maxBytes: number;
|
|
||||||
}): number {
|
|
||||||
const total = params.total + params.bytesRead;
|
|
||||||
if (total > params.maxBytes) {
|
|
||||||
throw new RangeError(`File exceeds ${params.maxBytes} bytes`);
|
|
||||||
}
|
|
||||||
params.chunks.push(Buffer.from(params.scratch.subarray(0, params.bytesRead)));
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Read at most maxBytes from the descriptor without an unbounded allocation. */
|
|
||||||
export function readFileDescriptorBoundedSync(fd: number, maxBytes: number): Buffer {
|
|
||||||
const chunks: Buffer[] = [];
|
|
||||||
const scratch = createScratchBuffer(maxBytes);
|
|
||||||
let total = 0;
|
|
||||||
while (true) {
|
|
||||||
const bytesRead = fs.readSync(fd, scratch, 0, scratch.length, null);
|
|
||||||
if (bytesRead === 0) {
|
|
||||||
return Buffer.concat(chunks, total);
|
|
||||||
}
|
|
||||||
total = appendChunk({ chunks, scratch, bytesRead, total, maxBytes });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function readChunk(fd: number, scratch: Buffer): Promise<number> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
fs.read(fd, scratch, 0, scratch.length, null, (error, bytesRead) => {
|
|
||||||
if (error) {
|
|
||||||
reject(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve(bytesRead);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Async variant for request paths; caller retains descriptor ownership. */
|
|
||||||
export async function readFileDescriptorBounded(fd: number, maxBytes: number): Promise<Buffer> {
|
|
||||||
const chunks: Buffer[] = [];
|
|
||||||
const scratch = createScratchBuffer(maxBytes);
|
|
||||||
let total = 0;
|
|
||||||
while (true) {
|
|
||||||
const bytesRead = await readChunk(fd, scratch);
|
|
||||||
if (bytesRead === 0) {
|
|
||||||
return Buffer.concat(chunks, total);
|
|
||||||
}
|
|
||||||
total = appendChunk({ chunks, scratch, bytesRead, total, maxBytes });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -656,12 +656,12 @@ describe("secret ref resolver", () => {
|
|||||||
|
|
||||||
const sampleHandle = await fs.open(filePath, "r");
|
const sampleHandle = await fs.open(filePath, "r");
|
||||||
const fileHandlePrototype = Object.getPrototypeOf(sampleHandle) as {
|
const fileHandlePrototype = Object.getPrototypeOf(sampleHandle) as {
|
||||||
readFile: typeof sampleHandle.readFile;
|
read: typeof sampleHandle.read;
|
||||||
};
|
};
|
||||||
await sampleHandle.close();
|
await sampleHandle.close();
|
||||||
const readFileSpy = vi
|
const readSpy = vi
|
||||||
.spyOn(fileHandlePrototype, "readFile")
|
.spyOn(fileHandlePrototype, "read")
|
||||||
.mockImplementation(() => new Promise<Buffer>(() => {}) as never);
|
.mockImplementation(() => new Promise(() => {}) as never);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await expect(
|
await expect(
|
||||||
@@ -681,7 +681,7 @@ describe("secret ref resolver", () => {
|
|||||||
),
|
),
|
||||||
).rejects.toThrow('File provider "filemain" timed out');
|
).rejects.toThrow('File provider "filemain" timed out');
|
||||||
} finally {
|
} finally {
|
||||||
readFileSpy.mockRestore();
|
readSpy.mockRestore();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ describe("check-package-patches", () => {
|
|||||||
`packages:
|
`packages:
|
||||||
- .
|
- .
|
||||||
patchedDependencies:
|
patchedDependencies:
|
||||||
"@openclaw/fs-safe@0.4.1": "patches/@openclaw__fs-safe@0.4.1.patch"
|
|
||||||
"baileys@7.0.0-rc12": "patches/baileys@7.0.0-rc12.patch"
|
"baileys@7.0.0-rc12": "patches/baileys@7.0.0-rc12.patch"
|
||||||
`,
|
`,
|
||||||
"utf8",
|
"utf8",
|
||||||
@@ -69,13 +68,11 @@ patchedDependencies:
|
|||||||
path.join(dir, "pnpm-lock.yaml"),
|
path.join(dir, "pnpm-lock.yaml"),
|
||||||
`lockfileVersion: '9.0'
|
`lockfileVersion: '9.0'
|
||||||
patchedDependencies:
|
patchedDependencies:
|
||||||
"@openclaw/fs-safe@0.4.1": fs-safe-hash
|
|
||||||
baileys@7.0.0-rc12: a9aea1790d2c65b1ae543c77faca4119bbfb91ee3b6ca6c38d1cad4f5702ada2
|
baileys@7.0.0-rc12: a9aea1790d2c65b1ae543c77faca4119bbfb91ee3b6ca6c38d1cad4f5702ada2
|
||||||
`,
|
`,
|
||||||
"utf8",
|
"utf8",
|
||||||
);
|
);
|
||||||
writeFileSync(path.join(dir, "patches", "baileys@7.0.0-rc12.patch"), "diff\n", "utf8");
|
writeFileSync(path.join(dir, "patches", "baileys@7.0.0-rc12.patch"), "diff\n", "utf8");
|
||||||
writeFileSync(path.join(dir, "patches", "@openclaw__fs-safe@0.4.1.patch"), "diff\n", "utf8");
|
|
||||||
git(dir, ["add", "pnpm-workspace.yaml", "pnpm-lock.yaml", "patches"]);
|
git(dir, ["add", "pnpm-workspace.yaml", "pnpm-lock.yaml", "patches"]);
|
||||||
|
|
||||||
expect(collectPackagePatchViolations(dir)).toEqual([]);
|
expect(collectPackagePatchViolations(dir)).toEqual([]);
|
||||||
|
|||||||
Reference in New Issue
Block a user