diff --git a/.github/codeql/codeql-network-ssrf-boundary-critical-security.yml b/.github/codeql/codeql-network-ssrf-boundary-critical-security.yml index 32e817b4f8c6..6b0d0e69ffbe 100644 --- a/.github/codeql/codeql-network-ssrf-boundary-critical-security.yml +++ b/.github/codeql/codeql-network-ssrf-boundary-critical-security.yml @@ -21,7 +21,6 @@ paths: - src/plugin-sdk/ssrf-policy.ts - src/web-fetch - src/web/provider-runtime-shared.ts - - packages/memory-host-sdk/src/host/ssrf-policy.ts - packages/net-policy/src paths-ignore: diff --git a/docs/.generated/plugin-sdk-api-baseline.sha256 b/docs/.generated/plugin-sdk-api-baseline.sha256 index cd459068c6b6..92f606896133 100644 --- a/docs/.generated/plugin-sdk-api-baseline.sha256 +++ b/docs/.generated/plugin-sdk-api-baseline.sha256 @@ -3,10 +3,10 @@ b41e6e6f7a1197d85922d010de1abf1de64f25c535200f6506a8c9b4334952f1 module/account 71522995185b956a0cc4927a472cc8d1153e5e998874bfd9a750513175174713 module/account-id 1f9b6f85f7886fcca451930f5be6898ba917f9a9c01973fc7cc0c76929bdcc76 module/account-resolution 4fbb1c87e99399f842a20d75d5e35a4b7064a1b7f02115c23f9a2a7cdcfb57ee module/agent-config-primitives -24435a0dd66cf2ae849d37fa49e42973b3cf5b600356ef4b71d4316e0ea524c0 module/agent-harness -0ebf919002fa124e4e634d5629c3e7a040fdc29148ce879166f2c4ffdd89c2f1 module/agent-harness-runtime +8791c48864f7d5b3aa4a9202741c252dbf8c36a901d575d47ab02830c8c2edf1 module/agent-harness +0125b0c97adb16e6db96e4098a0b18008679ad454b9f036dd780f28da2269d93 module/agent-harness-runtime d6097cfa1b410f4b5267a56a7bd19c2a33fbaf6642683dae6aec68e998e48f6c module/agent-media-payload -08a2a87ff549d1a7b19a681cbea3a0f0e7bb57851711b5808d321766f25dc5fb module/agent-runtime +076faadad74fd3cb2d2527a9693ed163c9fa178b6f5e8c1d5fe907e24fe8336d module/agent-runtime cbcd1201250087b16f41e87cd5b9d3be303620dd27e945b619e7117a5dbc069f module/agent-scope-runtime 8fecb210e22bce4532b6ab649b09465f0bd2c857a44abf40db7d683d6491e6da module/allow-from af6c69278be1aaab26d97dcc27cdfd73f56b3f18df327e71f346a75882a09436 module/allowlist-config-edit @@ -26,19 +26,19 @@ b33ade7748d6818914a6e9b9a23b98d0140432f5dcbe1f000a84d76617e9f639 module/channel c2cc71d5070b6071c51248b0648d1ad1a9468d3737df890adc77ec02025e8853 module/channel-config-primitives a6cca5706f3aba6abb2178b175a0986d921ade98c2c05d2a54451e2fb7e16825 module/channel-config-schema e4e4a5e78619abf1c8d78dd00d90e9bc8fe748adbf8a0dadbf0d9052bfcf5ab1 module/channel-contract -cb5ebdcdcc16a44938be23d5928c0454b70e7ecb5108d520a86cc7ba3a99c73d module/channel-core +cf098ed89f10e92a275ec49146dc718baad919dfcada10aa59fad1f6b0a887b9 module/channel-core f6596a8bcf85e9cfeb29e785c0f3b21fe438e07b1a4f179b9ec49c624516ed72 module/channel-dm-policy -0607eb29d92dbd3a660036db16f71206e856dcf185b5c8aa31cb81cbda60acd9 module/channel-entry-contract +c412bffcd394dc07d559527c26e31f466a2aa76a900bc7a78c16c7afb906c6e3 module/channel-entry-contract 47cf8765e76c151ae7d2991d41beca62922a8837c1521e10a3fd23f9992c2d7c module/channel-feedback -438efc8394e4d79b4f4553a58a92f5435c7930d0541ac2c158745a4eb35332c3 module/channel-inbound +d06b10a06868e5793c4f20f6ec6c4c0264c1217767cef607608a82d39dd738ed module/channel-inbound 3115366026efa38e07bfe0bfecd483e93454cc7bcad432385139c956777accff module/channel-inbound-debounce bc59c696ee45fb500d105c619c0ec81b8186bebe99135f23dc818ac16004deb0 module/channel-ingress-runtime bf81078cfeebe50ac260a3b6e56d842756f24ed2dd9af1a29f00a3ff2039be93 module/channel-lifecycle 0e47457e38d1df0bd572e1408cde2ca6a788b65205f43c585316b5ad3a8f2f16 module/channel-logging -b89692a3a9b8fd10a0dd776151f25ef94da8cb55c2557f05060e94726c5acefb module/channel-message -45bd9548c7194d14bae0501452d3a3c8c1d1fcf627384611af0700e7407d0940 module/channel-outbound -5e759b34528808911b545abf74bdf3b6d14ecc69d8c4b5ab07e2a344a8e66f66 module/channel-pairing -8145974cb88959db29d3e09bef7807446a157965596ae902d7ca4c616c7269d3 module/channel-plugin-common +757fca9e3889f35e3f81980a0f7d559a8231000e7427bf59fc847a0c720cb291 module/channel-message +059710480d2c728609a8fdbb6b1a8012f32c1c08a88460f3a2f34bcacb67d525 module/channel-outbound +55e38ea1273e37c0f035cc36e352170498b521ab20a4a93d25d6cdb6acbf15df module/channel-pairing +746e8a837f7aff515215157270c6fe3207eeba309186e9bf20f10a0d72f1b6c4 module/channel-plugin-common e9f6fa5006304028e54f4ee84f1b006c14356b9f64b9c8508491cdae5290ccfd module/channel-policy 3c454d34f2c70b1741c2c977bd1367004c5d0e79ee44f3aece7345e40bc84394 module/channel-reply-pipeline 482370e60135db9bfaf07f24bab549e5fde09ab265a6061a1f587c5d93929e91 module/channel-runtime-context @@ -51,8 +51,8 @@ f6c25ae55d49d90431682ca53c9dd836304942a738425d6ff028146a0c6d2c97 module/channel b2f920ff4a6b4190e6d6ea0a3effb001751e092f0e3ac0cf296721ff8c383d86 module/channel-streaming-config fdeffe356c7c4edeec9f8fd03edcadc375eabc7a9412e582b10c3180e3ef40fc module/cli-argv ad12670dbfe538f8d0ebf4fb2b68080e93a760278278e6b1ce9bb129d4b2d533 module/collection-runtime -fae9d384e3da9f0cf6de490835530b6a5d70eec76a4bb2097839e0cd3432bcc1 module/command-auth -5592ad29779bf4379ad227ad6b2557d67881a535b8121b6ab955ae7f089a7ab4 module/command-auth-native +b2e8c02d09eb3bd3c7645bc37ba0785be1c0fbbd742eeafdf6e9e109b4377fc1 module/command-auth +1ab2991c220b55cd96041c3dc70956cf1e01b8aa45a8d8b130d32a6683001ac5 module/command-auth-native 50c24235bca2c1d3c011f6bc266b57078b78a76d2d27ee12e7b3245f2947b493 module/command-detection e24382c2cca7fd2cf69ac353e258153dab80b279daf9f0ef54a727981a7dff3c module/command-primitives-runtime 1d6ebcdc843b7072a7fc4475eadadb90a1111d49c1da1e4326775800873cf9f1 module/command-status @@ -60,12 +60,12 @@ e24382c2cca7fd2cf69ac353e258153dab80b279daf9f0ef54a727981a7dff3c module/command 0d99f5cb8c4978ed760e5fb4e476543759fbd8fd5bf73cc50a50c1d550203826 module/config-mutation 5153d66e931ca8c9c5a6102460da637fcb9e6c7e1db94d67ef7e5970b6a8d42d module/config-runtime a87d663700604d7ca14a2b3f7e047c67633182cbe60f1f18bb78782240a4886b module/conversation-runtime -b72b1c3ad055f040052d08701c9010c05c86af4d802ef19a9b3a79a370a59b4e module/core -c23937aa85d60bf64c5570d3d267f559423f1389a0d1bd26c90e0facca414f99 module/dedupe-runtime +8d188be6c7a095fba512eed9d89a8fc1f0a1d307d388df2fda74eed73d36d59b module/core +7c0e4d56dab3c0239e4a1904e6a5ef1bef07ad8a1efe40a973ba11e1b14a91d0 module/dedupe-runtime ebef0e650ab45e44c9335e2b3e15588c968cea6dadd125364a076f9c50ad1e8c module/device-bootstrap 21d86413166ef815581d606f678b6a216a1cc73ffe470b841f5bc4a131bff6df module/diagnostic-runtime 6c697283dd82402fd84b97b5226086575a23ec36ba5bf915b650fb9ee21df9ad module/directory-runtime -9872aaef4544f06bbf14d199decab4646c4ae3b5248609884932d641c160c953 module/discord +b4581ed2ac4eccf395b7c052178621ef06879226f73cdd1722dc42e790deb9e6 module/discord 39fe343ed2119de714757c365eef2ccec89c2c82a0876c60a4bef8ce469f8c8a module/error-runtime ce4f1602bf5b5de968ca97cede4f498b6ae709a0a59393b5ce9255cf0e6a9d5e module/extension-shared dd9f6e0fd33cc88b22543c1ee30cc09cf4de4d8f30dff7b7f9cebef885c21543 module/gateway-method-runtime @@ -75,7 +75,7 @@ edcc13362193d3bb0b16fc48a3d96122e6efa236cfdec3760e57e2c6d85ee8b8 module/health 69d49c9cd6cf270df7dc1c6babb0c53c7ed1e60e9e2da102eecbda0226b2278e module/hook-runtime a953bd0c23c562e29fc512bc2354ed45c497728169d8201cb2cdb75d9e056073 module/inbound-envelope 4928af5d2509f696b896f53ac790303a0742202dbcdae3e44fe6d1b434a9c1ba module/inbound-event-delivery -c2471f270314e68db1ef13c3f3424c9bec3469cdd2b0a2be860d07eab7a1fc08 module/inbound-reply-dispatch +271c40917a54400de91b269f1f95c381dbecc8f98113f6d9828eeebd3e83ebfd module/inbound-reply-dispatch f0247897efdea3bff60314e68a0ad41aff9d6835b43a4c443044eb5fade503f8 module/infra-runtime ce73721421f1b903dd04ead4df173582e59ea3e9990248102c448b419cc6d272 module/ingress-effect-once 9c6e3796569c6a27762946281a5c1a792158505651ae5e9434e5d18ebd9ee947 module/interactive-runtime @@ -89,28 +89,28 @@ f74d7295fe716aa140aa0bc9300d6259d71dab826de0808fca6bb02592bf5d6e module/media-m 6a52f93107335f88751704352cc01e62add06f854a5b7d765e2a5ee87c0313b6 module/media-store 3bdcc734f6ea5f59320708cb2b87de9c5422a8b70745774ea0cc8a01cf656924 module/media-understanding 4e64c47aed06c23796a07f099b7ab52ee68feeb7c934c749c5cdcd7cb9ef6e7b module/media-understanding-runtime -47998f7300f028505fdf9b538a857aa34b64d85fc981283d4029b4198e381a06 module/meeting-runtime +73ae8562bcda4f26b44348302f9169b2ce15b282bc19d2065128c267ef9164d3 module/meeting-runtime 3312468e2e8f3423b765fac6bb17944b800ea2c84acffeb64342c99040b2f482 module/memory-core-host-engine-foundation -52777f617938178c38f914110127850d65bff28e65583a2078479ad60b576752 module/memory-host-core +b57de21d9676dc0df41d59b895c434700e767bbcab454fa8fac0379b5c066967 module/memory-host-core 1efa0aadc4261d1c6073058cbf3dcc9fa681424819bdd14333e19b249bbc4b18 module/messaging-targets 8a43f27e4b4cc71aa92d0fdde83c9374ad155f74bb2ec7db1d48559065a8772d module/model-session-runtime -a08ce01664e301346d8e1b2ce13e2bdaabc126248437665858b1e10de5bd893f module/models-provider-runtime +2902259327d96199b4753b871251edec12265dbf70a7c12d8f5f863db5743b6a module/models-provider-runtime a3eaaf99e2ac5e83f0e14b83ae54a2d99488a6597df0c4421a0d58cdc1bd3fd7 module/native-command-config-runtime f6ffada942145ca2fcec4df90740b4578afa09e81d46cc09122a65d6e345fe02 module/native-command-registry a6b5532576fa4cfd609d0966927eec12806424f2e1efce9fe47d903dfeb8e4dd module/param-readers ca7a56bb1a6169b4cf9befbf5aa21da280a8086fdc49fca4eec520a7a7c98549 module/persistent-dedupe b31f5d86904097993a55377fed7973cd298b0e1f49cade7e37a1e28f6e724108 module/plugin-config-runtime -26a1f738674de568ccf0356c98b680907d808d7da5cbfdefd0cba22e7c5c2093 module/plugin-entry -9ef4553306dc9175a0aa2f75cb84653d13104d06f29b49210fe5853fc3a535e6 module/plugin-runtime -6bbf69a676642339991e6712b50de580fb18e812029c3b845ebf2ceba485cf0d module/provider-auth -7c9cf3ca6315304e05afb726f928293010932b3d85607b684be67083470cdaba module/provider-catalog-runtime +a2f3f20742849b14599685bd98b083f1454b2f56c8363f30f0d49789b41d612d module/plugin-entry +fd39068d4eefdc8804ce84d4621cc94877047dccf07c9092a40020cfc2e5f9de module/plugin-runtime +f7770b96b0a1b152d7aa9619d2e19f9a637ce25e36cab9c23ce030565eea870a module/provider-auth +d2a40746f617fbeb758c4606a299b5f00be13aa86676de26b249a9abf291a775 module/provider-catalog-runtime 8131147d699394bd06503e2ea2f5f1a50b1594a87dded6d118b74a8d0328c8f6 module/proxy-capture a6c6462326817540b9d654f0254bf561a340ba058851e958fd0367aaa9198b9a module/question-gateway-runtime 50e250d810a9936ae468710698a61e8e569f728f2f3f55fb57ea1e401b3a37be module/reply-chunking -48544c5cbcb58c30ed04a6744967573ba653e29fbe506e314f3ae84c8f891c9e module/reply-dispatch-runtime +54c342c161d75b85b992f1aeb798c98ded01555411a48edad80dc30c24ba1ad8 module/reply-dispatch-runtime 73f861fa3179d5af1159853c5acab0eec7a6c8f9398dcb75ea770e784fca6727 module/reply-history 321f9ecc06267499c7700c17f96d58bfd1e56d09fd765bb8ce4b6664427720ff module/reply-payload -4c8116251dd4166536534b652962191c881a471c33fb4d2abe98279a9f4face8 module/reply-runtime +3453ad8d356b46b6ff7fca1ed6bb1b096373dcc74d6e212915f3efc2063bdd43 module/reply-runtime aa07d85d99fdd2b1e0cbe9975fb6dcae66b8bdce2607c6bd5402ae68bb15118c module/root-walk ad6c5c5b16e22f8b06994f69ecfafbc9a9622b07c14670f3c4e8ee81cf3b8c4d module/routing 7877a7e58fa32a64107154e5b714c6d165e96989d4aa5f43e0afac085a187af0 module/run-command @@ -118,20 +118,20 @@ ad6c5c5b16e22f8b06994f69ecfafbc9a9622b07c14670f3c4e8ee81cf3b8c4d module/routing 0570a20fac6020880900a0cf9a889d8f28f47b89d0e1d17862265b557236d440 module/runtime-config-snapshot bfe087e249a3c0adda4d24727220a65bcc159f53d6a4d6d8cd9b252627ef8e98 module/runtime-env 49e9b6a8195c89704eaa80656f176444af7cacbf639b759f41f2c78ae6bfcfd9 module/runtime-group-policy -ce2696a2ef054ff86c75cdfcf64434c8833139db2167883210d259fd1b39006d module/runtime-store +c57fba7d4e6eca193cf6896eb7ace28683733e192404fe0f6d7421a2b2aa6852 module/runtime-store d17862c40825af1ddf0257b44f1e1cbb9c375e8e5ed668fae75d530d1a465cf9 module/secret-file 8e2ac4d3973d8d8ce4478e3440d66ee5c0d9213b0fe9e927c421d14fd31e5e86 module/secret-input b1b0229280d7cc4a880e4db75130714eb6adc9d6aea31240dc9a8ff6fda55219 module/secret-input-runtime 0cbc3908bd9e1d4527585023a1692eba6c0bfe82f107f49a926a8d1c79aee2a0 module/secret-ref-runtime efac9b2e9828a4d2f45794bfea8a9c0ce92578164f6012a9d2d83418d0bd7ba8 module/security-runtime -e768be7cc333145220e5b505b24cb80fe6de8f817d5fc8ccd7cdf091bafcffa9 module/session-catalog -86c0555dcc0a6cec6488f91af5c8d1db932341e1e0d2d2b8a14649088a72cd42 module/session-discussion +c20154becd67047940393057af0758a287a09e052bb77f83463a6e87c1484ff9 module/session-catalog +01c150ef10d33839f86107b05fcfb7bc3dc0883c7dafd1e065758678caf7c9aa module/session-discussion 8d71e05167eb3301536e9f7e8fc14047791c28a4e32c014746db5b3dd0477242 module/session-store-runtime 124f36c843153cb31b85bbe061a145ee768251b82fc31ffdd0b9c7cab472f9b2 module/setup a2b1f5da3a82d501171a88f759c9dd756286df8884703168da97d8cd4aa2b1c9 module/setup-runtime d0cb4c5abb7484352088f556c1ba7c7b147d7b57977b8246e5cb7187937768b7 module/setup-tools 41cb221e60e0285e00c926af872b222ed089f745c70d3c513476f96f6736de8b module/skill-commands-runtime -46e1286735fefd131db738d12ae9209a16f7a7212f6eb3e304a91e8c708616f0 module/speech-settings +ac554f41638bb2780d9b53cfc76fc9c8d361a587ddba234804cdd67a91a823de module/speech-settings 614e35857fd3891aefd1a49955140e0e78c5bf9c4e3950268b9e28f4eeed6f9d module/ssrf-policy b84d7ab7506041897a22e3cc5ba7f62e90fdcdbea91e38a71030b79cca2d77ed module/ssrf-runtime 3855f0a23281d21063762f5b3be2b7485c8bdb3b4cd1692de4f2a17d4eeae496 module/state-paths @@ -141,11 +141,11 @@ f097d0096b21c8a052f0f649b7512ecf2aba4744ae6956f001950e053828b309 module/string- aef35bee2502cd6ed8765409b758e452aff8ac9469fd773e6a2a44c9a1bc3f66 module/temp-path 87fa81b9e58d8fc04a4b4202d2d37fca339615f5225687d9db905151439e0f4d module/text-chunking fcdaf13ecea269f1a471ba4fe14958f3c8e198eaa20f354546a648408ed74064 module/text-runtime -75a65ee4ac2c28a4dc82c0dd94d822f11d231b97a8614439138e0dd1b73315a2 module/tool-plugin +903548ea9a01c9f5853870a168b523028b7787253015d9a7732ce5e54480800a module/tool-plugin dc1a073c59ab61e2789533b777b3f0cb9af689d64a97796b10e8aa82552510db module/tool-results 1aa65cefa239d5943f19c2cf2a19c37857b0b659452877fc457dbf627a28fff0 module/tool-send cda105b721d498df23a554c6b68be150b8fe66b8b9172185c31a0b3b0646b1dc module/web-media -0cbc8da0c86232ead208c2613c116e3f3bcd4cfe221d01cb095a7a6403bc8313 module/webhook-ingress +14e040a528b00146a4df1fe994d69db028fa14b043ae7a01cce26472d7445133 module/webhook-ingress e3a199a9ce0b85d203e9e8a29b500db29c6b7af307e3145d0a311e29d598925b module/webhook-request-guards de59e86e126b75d13251cba7ebbe27b44d9b5588785d98df5ff4d6722374c81f module/widget-html 9161b36ec0ab062ea41b363c894fcd672a7727f21cb726739f99f9c184fce69d module/zod diff --git a/packages/acp-core/src/error-format.test.ts b/packages/acp-core/src/error-format.test.ts index 8bc8e120891b..1221171224fd 100644 --- a/packages/acp-core/src/error-format.test.ts +++ b/packages/acp-core/src/error-format.test.ts @@ -26,8 +26,8 @@ describe("redactSensitiveText", () => { it("applies fallback secret redaction after a configured redactor", () => { configureAcpErrorRedactor((value) => value.replace("prefix", "host-redacted")); try { - expect(redactSensitiveText("prefix ghp_123456789012345678901234")).toBe( - "host-redacted [REDACTED]", + expect(redactSensitiveText("prefix TOKEN=standalone-secret")).toBe( + "host-redacted TOKEN=[REDACTED]", ); } finally { configureAcpErrorRedactor(undefined); diff --git a/packages/acp-core/src/error-format.ts b/packages/acp-core/src/error-format.ts index d0f0cfd04784..6925e84bf4de 100644 --- a/packages/acp-core/src/error-format.ts +++ b/packages/acp-core/src/error-format.ts @@ -13,6 +13,8 @@ import { const STRUCTURED_AUTH_MARKER_PREFIX = ";__openclaw_structured_auth_redacted_"; +// Minimal fallback for standalone or unwired ACP core. OpenClaw injects canonical +// redaction via configureAcpErrorRedactor; grow src/logging/redact-patterns.ts, not this table. const SECRET_PATTERNS: RegExp[] = [ /\b[A-Z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|CARD[_-]?NUMBER|CARD[_-]?CVC|CARD[_-]?CVV|CVC|CVV|SECURITY[_-]?CODE|PAYMENT[_-]?CREDENTIAL|SHARED[_-]?PAYMENT[_-]?TOKEN)\b\s*[=:]\s*(["']?)([^\s"'\\]+)\1/g, /\b[A-Z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|CARD[_-]?NUMBER|CARD[_-]?CVC|CARD[_-]?CVV|CVC|CVV|SECURITY[_-]?CODE|PAYMENT[_-]?CREDENTIAL|SHARED[_-]?PAYMENT[_-]?TOKEN)\b\s*[=:]\s*\\+(["'])([^\s"'\\]+)\\+\1/g, @@ -50,24 +52,6 @@ const SECRET_PATTERNS: RegExp[] = [ /\bBearer\s+([-A-Za-z0-9._~+/=]{18,})(?![-A-Za-z0-9._~+/=])/g, /(^|[\s,;])(?:access_token|refresh_token|auth[-_]?token|api[-_]?key|client[-_]?secret|app[-_]?secret|token|secret|password|passwd|card[-_]?number|card[-_]?cvc|card[-_]?cvv|cvc|cvv|security[-_]?code|payment[-_]?credential|shared[-_]?payment[-_]?token)=([^\s&#]+)/gi, /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]+?-----END [A-Z ]*PRIVATE KEY-----/g, - /\b(sk-[A-Za-z0-9_-]{8,})\b/g, - /(ghp_[A-Za-z0-9]{20,})/g, - /(github_pat_[A-Za-z0-9_]{20,})/g, - /(xox[baprs]-[A-Za-z0-9-]{10,})/g, - /(xapp-[A-Za-z0-9-]{10,})/g, - /(gsk_[A-Za-z0-9_-]{10,})/g, - /(AIza[0-9A-Za-z\-_]{20,})/g, - /(ya29\.[0-9A-Za-z_\-./+=]{10,})/g, - /(1\/\/0[0-9A-Za-z_\-./+=]{10,})/g, - /(eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,})/g, - /(pplx-[A-Za-z0-9_-]{10,})/g, - /(npm_[A-Za-z0-9]{10,})/g, - /(AKID[A-Za-z0-9]{10,})/g, - /(LTAI[A-Za-z0-9]{10,})/g, - /(hf_[A-Za-z0-9]{10,})/g, - /(r8_[A-Za-z0-9]{10,})/g, - /\bbot(\d{6,}:[A-Za-z0-9_-]{20,})\b/g, - /\b(\d{6,}:[A-Za-z0-9_-]{20,})\b/g, ]; let configuredRedactor: ((value: string) => string) | undefined; @@ -111,7 +95,7 @@ export function configureAcpErrorRedactor(redactor: ((value: string) => string) configuredRedactor = redactor; } -/** Redacts common provider, GitHub, HTTP, payment, bot, and private-key secrets from error text. */ +/** Redacts common HTTP, payment, assignment, and private-key secrets from error text. */ export function redactSensitiveText(value: string): string { const configured = configuredRedactor ? configuredRedactor(value) : value; const structuredAuthMarker = createStructuredAuthMarker(configured); diff --git a/packages/acp-core/src/runtime/errors.test.ts b/packages/acp-core/src/runtime/errors.test.ts index 2846c15f7c52..d0143fa6017e 100644 --- a/packages/acp-core/src/runtime/errors.test.ts +++ b/packages/acp-core/src/runtime/errors.test.ts @@ -162,13 +162,9 @@ describe("formatAcpErrorChain redaction", () => { expect(out).not.toContain(token); }); - it("redacts common HTTP, provider, and private-key credentials in ACP error text", () => { + it("redacts common HTTP and private-key credentials in ACP error text", () => { const secrets = [ "Authorization: Basic dXNlcjpwYXNzd29yZGFiY2RlZg==", - "Bearer eyJabcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz", - "github_pat_abcdefghijklmnopqrstuvwxyz123456", - ["xoxb", "1234567890", "abcdefghijklmnop"].join("-"), - "bot123456789:abcdefghijklmnopqrstuvwxyz123456", "-----BEGIN PRIVATE KEY-----\nabcdefghijklmnopqrstuvwxyz\n-----END PRIVATE KEY-----", ]; const out = formatAcpErrorChain( diff --git a/packages/memory-host-sdk/src/host/batch-http.ts b/packages/memory-host-sdk/src/host/batch-http.ts index 101c43704c8b..dc02bd966c60 100644 --- a/packages/memory-host-sdk/src/host/batch-http.ts +++ b/packages/memory-host-sdk/src/host/batch-http.ts @@ -1,7 +1,7 @@ // Memory Host SDK module implements batch http behavior. import { retryAsync } from "@openclaw/retry"; +import type { SsrFPolicy } from "./openclaw-runtime-network.js"; import { postJson } from "./post-json.js"; -import type { SsrFPolicy } from "./ssrf-policy.js"; // JSON POST helper for batch APIs with provider-style transient retry. diff --git a/packages/memory-host-sdk/src/host/batch-utils.ts b/packages/memory-host-sdk/src/host/batch-utils.ts index 66ea9a39d985..1debfa36ff9d 100644 --- a/packages/memory-host-sdk/src/host/batch-utils.ts +++ b/packages/memory-host-sdk/src/host/batch-utils.ts @@ -1,5 +1,5 @@ // Memory Host SDK helper module supports batch utils behavior. -import type { SsrFPolicy } from "./ssrf-policy.js"; +import type { SsrFPolicy } from "./openclaw-runtime-network.js"; // Common HTTP and grouping helpers for remote embedding batch clients. diff --git a/packages/memory-host-sdk/src/host/embeddings-remote-client.ts b/packages/memory-host-sdk/src/host/embeddings-remote-client.ts index afab7004aaa0..9bb863c867dc 100644 --- a/packages/memory-host-sdk/src/host/embeddings-remote-client.ts +++ b/packages/memory-host-sdk/src/host/embeddings-remote-client.ts @@ -2,9 +2,9 @@ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; import type { EmbeddingProviderOptions } from "./embeddings.types.js"; import { requireApiKey, resolveApiKeyForProvider } from "./openclaw-runtime-auth.js"; +import type { SsrFPolicy } from "./openclaw-runtime-network.js"; import { buildRemoteBaseUrlPolicy } from "./remote-http.js"; import { resolveMemorySecretInputString } from "./secret-input.js"; -import type { SsrFPolicy } from "./ssrf-policy.js"; // Builds authenticated remote embedding HTTP clients from agent memory config. diff --git a/packages/memory-host-sdk/src/host/embeddings-remote-fetch.ts b/packages/memory-host-sdk/src/host/embeddings-remote-fetch.ts index 3387661b5185..d111dbbc4b8e 100644 --- a/packages/memory-host-sdk/src/host/embeddings-remote-fetch.ts +++ b/packages/memory-host-sdk/src/host/embeddings-remote-fetch.ts @@ -1,7 +1,7 @@ // Memory Host SDK module implements embeddings remote fetch behavior. import { asOptionalRecord } from "@openclaw/normalization-core/record-coerce"; +import type { SsrFPolicy } from "./openclaw-runtime-network.js"; import { postJson } from "./post-json.js"; -import type { SsrFPolicy } from "./ssrf-policy.js"; // Fetches and validates OpenAI-compatible embedding responses. diff --git a/packages/memory-host-sdk/src/host/embeddings-remote-provider.ts b/packages/memory-host-sdk/src/host/embeddings-remote-provider.ts index bc1bff19bce9..1b00db6d7ac3 100644 --- a/packages/memory-host-sdk/src/host/embeddings-remote-provider.ts +++ b/packages/memory-host-sdk/src/host/embeddings-remote-provider.ts @@ -5,7 +5,7 @@ import { } from "./embeddings-remote-client.js"; import { fetchRemoteEmbeddingVectors } from "./embeddings-remote-fetch.js"; import type { EmbeddingProvider, EmbeddingProviderOptions } from "./embeddings.types.js"; -import type { SsrFPolicy } from "./ssrf-policy.js"; +import type { SsrFPolicy } from "./openclaw-runtime-network.js"; // Remote embedding provider factory for OpenAI-compatible embeddings APIs. diff --git a/packages/memory-host-sdk/src/host/error-utils.test.ts b/packages/memory-host-sdk/src/host/error-utils.test.ts index c883e0157c04..4e9f3a4dd712 100644 --- a/packages/memory-host-sdk/src/host/error-utils.test.ts +++ b/packages/memory-host-sdk/src/host/error-utils.test.ts @@ -1,33 +1,102 @@ // Memory Host SDK tests cover error formatting and secret redaction. -import { describe, expect, it } from "vitest"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import { afterEach, describe, expect, it } from "vitest"; +import { withEnv } from "../../../../src/test-utils/env.js"; import { formatErrorMessage } from "./error-utils.js"; const TOKEN_CASES = [ - ["leading split", "abcde😀xxxxxxxxwxyz", "abcde...wxyz"], - ["trailing split", "abcdefghijklm😀xyz", "abcdef...xyz"], - ["intact leading pair", "abcd😀xxxxxxxxwxyz", "abcd😀...wxyz"], - ["intact trailing pair", "abcdefghijklmn😀xy", "abcdef...😀xy"], + ["leading surrogate boundary", "abcde😀xxxxxxxxwxyz"], + ["trailing surrogate boundary", "abcdefghijklm😀xyz"], + ["intact leading pair", "abcd😀xxxxxxxxwxyz"], + ["intact trailing pair", "abcdefghijklmn😀xy"], ] as const; +let tempDirs: string[] = []; + +function writeConfig(source: string): string { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-memory-redact-config-")); + tempDirs.push(dir); + const configPath = path.join(dir, "openclaw.json"); + fs.writeFileSync(configPath, source); + return configPath; +} + +afterEach(() => { + for (const dir of tempDirs) { + fs.rmSync(dir, { force: true, recursive: true }); + } + tempDirs = []; +}); + describe("formatErrorMessage", () => { - it.each(TOKEN_CASES)("masks tokens with a UTF-16-safe %s", (_label, token, masked) => { - expect(formatErrorMessage(`TOKEN=${token}`)).toBe(`TOKEN=${masked}`); + it.each(TOKEN_CASES)("fully masks token assignments at a %s", (_label, token) => { + const output = formatErrorMessage(`TOKEN=${token}`); + expect(output).toBe("TOKEN=***"); + expect(output).not.toContain(token); }); - it("replaces the captured value literally when key and value repeat", () => { - expect(formatErrorMessage("LONG_LONG_LONG_TOKEN=LONG_LONG_LONG_TOKEN")).toBe( - "LONG_LONG_LONG_TOKEN=LONG_L...OKEN", - ); - expect(formatErrorMessage("TOKEN=$&abcdxxxxxxxxwxyz")).toBe("TOKEN=$&abcd...wxyz"); + it("redacts repeated key text and replacement metacharacters in values", () => { + const repeatedSecret = "prefix-LONG_LONG_LONG_TOKEN-suffix"; + const repeatedOutput = formatErrorMessage(`LONG_LONG_LONG_TOKEN=${repeatedSecret}`); + expect(repeatedOutput).toBe("LONG_LONG_LONG_TOKEN=prefix…ffix"); + expect(repeatedOutput).not.toContain(repeatedSecret); + + const replacementSecret = "$&abcdxxxxxxxxwxyz"; + const replacementOutput = formatErrorMessage(`TOKEN=${replacementSecret}`); + expect(replacementOutput).toBe("TOKEN=***&abcd…wxyz"); + expect(replacementOutput).not.toContain(replacementSecret); }); it("redacts bearer schemes case-insensitively", () => { - expect(formatErrorMessage("bearer memory/Start~opaque-memoryEnd")).toBe("bearer memory...yEnd"); + const secret = "memory/Start~opaque-memoryEnd"; + const output = formatErrorMessage(`bearer ${secret}`); + expect(output).toBe("bearer memory…yEnd"); + expect(output).not.toContain(secret); }); it("redacts quoted short bearer header values", () => { - expect(formatErrorMessage('{"Authorization":"bearer t7K4_x"}')).toBe( - '{"Authorization":"bearer ***"}', + const secret = "t7K4_x"; + const output = formatErrorMessage(`{"Authorization":"bearer ${secret}"}`); + expect(output).toBe('{"Authorization":"***"}'); + expect(output).not.toContain(secret); + }); + + it("redacts payment card and CVV assignments", () => { + const pan = "4242424242424242"; + const cvv = "123"; + const output = formatErrorMessage(new Error(`payment declined: card_number=${pan} cvv=${cvv}`)); + + expect(output).not.toContain(pan); + expect(output).not.toContain(`cvv=${cvv}`); + expect(output).not.toContain(cvv); + expect(output).not.toContain("4242424242"); + }); + + it("redacts JSON-shaped payment card fields", () => { + const pan = "4242424242424242"; + const output = formatErrorMessage(`{"cardNumber":"${pan}"}`); + + expect(output).not.toContain(pan); + expect(output).not.toContain("4242424242"); + }); + + it("merges operator redact patterns with provider-token coverage", () => { + const configPath = writeConfig(`{ + logging: { + redactPatterns: ["/internal-ticket-([A-Za-z0-9]+)/g"], + }, + }`); + const providerToken = `ghp_${"a".repeat(20)}`; + const customSecret = "internal-ticket-12345"; + + const output = withEnv({ OPENCLAW_CONFIG_PATH: configPath }, () => + formatErrorMessage(`memory failed: ${providerToken} ${customSecret}`), ); + + expect(output).not.toContain(providerToken); + expect(output).not.toContain(customSecret); + expect(output).toContain("memory failed"); }); }); diff --git a/packages/memory-host-sdk/src/host/error-utils.ts b/packages/memory-host-sdk/src/host/error-utils.ts index 3540a32e3983..ddf52bc7208d 100644 --- a/packages/memory-host-sdk/src/host/error-utils.ts +++ b/packages/memory-host-sdk/src/host/error-utils.ts @@ -1,72 +1,13 @@ // Memory Host SDK helper module supports error utils behavior. import { formatErrorMessage as formatSharedErrorMessage } from "@openclaw/normalization-core/error-coercion"; -import { sliceUtf16Safe } from "@openclaw/normalization-core/utf16-slice"; +// Import the canonical redactor directly, not via openclaw-runtime-io: that +// facade pulls the full core runtime (execa reach), and this module sits in the +// memory-core doctor contract closure, which the build guards keep execa-free. +import { redactToolPayloadText } from "../../../../src/logging/redact.js"; -const SECRET_PATTERNS: RegExp[] = [ - /\b[A-Z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD)\b\s*[=:]\s*(["']?)([^\s"'\\]+)\1/g, - /[?&](?:access[-_]?token|auth[-_]?token|hook[-_]?token|refresh[-_]?token|api[-_]?key|client[-_]?secret|token|key|secret|password|pass|passwd|auth|signature)=([^&\s"'<>]+)/gi, - /"(?:apiKey|token|secret|password|passwd|accessToken|refreshToken)"\s*:\s*"([^"]+)"/g, - /--(?:api[-_]?key|hook[-_]?token|token|secret|password|passwd)\s+(["']?)([^\s"']+)\1/g, - /["']?Authorization["']?\s*[:=]\s*(["']?)Bearer\s+([-A-Za-z0-9._~+/=]+)\1/gi, - /\bBearer\s+([-A-Za-z0-9._~+/=]+)(?![-A-Za-z0-9._~+/=])/gi, - /(^|[\s,;])(?:access_token|refresh_token|api[-_]?key|token|secret|password|passwd)=([^\s&#]+)/g, - /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]+?-----END [A-Z ]*PRIVATE KEY-----/g, - /\b(sk-[A-Za-z0-9_-]{8,})\b/g, - /\b(ghp_[A-Za-z0-9]{20,})\b/g, - /\b(github_pat_[A-Za-z0-9_]{20,})\b/g, - /\b(xox[baprs]-[A-Za-z0-9-]{10,})\b/g, - /\b(xapp-[A-Za-z0-9-]{10,})\b/g, - /\b(gsk_[A-Za-z0-9_-]{10,})\b/g, - /\b(AIza[0-9A-Za-z\-_]{20,})\b/g, - /\b(pplx-[A-Za-z0-9_-]{10,})\b/g, - /\b(npm_[A-Za-z0-9]{10,})\b/g, - /\bbot(\d{6,}:[A-Za-z0-9_-]{20,})\b/g, - /\b(\d{6,}:[A-Za-z0-9_-]{20,})\b/g, -]; - -// Redact common token/key shapes before errors leave memory host internals. -function maskToken(token: string): string { - if (token.length < 18) { - return "***"; - } - return `${sliceUtf16Safe(token, 0, 6)}...${sliceUtf16Safe(token, -4)}`; -} - -function redactPemBlock(block: string): string { - const lines = block.split(/\r?\n/).filter(Boolean); - if (lines.length < 2) { - return "***"; - } - return `${lines[0]}\n...redacted...\n${lines[lines.length - 1]}`; -} - -function redactMatch(match: string, groups: string[]): string { - if (match.includes("PRIVATE KEY-----")) { - return redactPemBlock(match); - } - const token = groups.findLast((value) => typeof value === "string" && value.length > 0) ?? match; - const masked = maskToken(token); - if (token === match) { - return masked; - } - const tokenOffset = match.lastIndexOf(token); - if (tokenOffset < 0) { - return "***"; - } - return `${match.slice(0, tokenOffset)}${masked}${match.slice(tokenOffset + token.length)}`; -} - -function redactSensitiveText(text: string): string { - let next = text; - for (const pattern of SECRET_PATTERNS) { - next = next.replace(pattern, (...args: string[]) => - redactMatch(args[0] ?? "", args.slice(1, -2)), - ); - } - return next; -} - -/** Format memory-host errors through the canonical formatter and local redaction policy. */ +/** Format memory-host errors through the canonical formatter and redaction policy. */ export function formatErrorMessage(err: unknown): string { - return formatSharedErrorMessage(err, { redact: redactSensitiveText }); + // Memory-host errors force redaction and merge operator patterns with defaults, + // so custom logging policy cannot disable provider-token coverage. + return formatSharedErrorMessage(err, { redact: redactToolPayloadText }); } diff --git a/packages/memory-host-sdk/src/host/openclaw-runtime-network.ts b/packages/memory-host-sdk/src/host/openclaw-runtime-network.ts index 59a6bdaee6a8..2f117ad3e359 100644 --- a/packages/memory-host-sdk/src/host/openclaw-runtime-network.ts +++ b/packages/memory-host-sdk/src/host/openclaw-runtime-network.ts @@ -3,3 +3,4 @@ export { fetchWithSsrFGuard } from "../../../../src/infra/net/fetch-guard.js"; export { shouldUseEnvHttpProxyForUrl } from "../../../../src/infra/net/proxy-env.js"; export { ssrfPolicyFromHttpBaseUrlAllowedHostname } from "../../../../src/infra/net/ssrf.js"; +export type { SsrFPolicy } from "../../../../src/infra/net/ssrf.js"; diff --git a/packages/memory-host-sdk/src/host/post-json.ts b/packages/memory-host-sdk/src/host/post-json.ts index 9b1b45fc05aa..ea037475c59d 100644 --- a/packages/memory-host-sdk/src/host/post-json.ts +++ b/packages/memory-host-sdk/src/host/post-json.ts @@ -1,11 +1,11 @@ // Memory Host SDK module implements post json behavior. import { formatErrorMessage } from "./error-utils.js"; +import type { SsrFPolicy } from "./openclaw-runtime-network.js"; import { withRemoteHttpResponse } from "./remote-http.js"; import { readMemoryHostResponseTextSnippet, readResponseJsonWithLimit, } from "./response-snippet.js"; -import type { SsrFPolicy } from "./ssrf-policy.js"; // Shared JSON POST helper for guarded remote memory provider calls. diff --git a/packages/memory-host-sdk/src/host/remote-error-redaction.test.ts b/packages/memory-host-sdk/src/host/remote-error-redaction.test.ts index 4ba9d66a84b4..4f3d5b79e276 100644 --- a/packages/memory-host-sdk/src/host/remote-error-redaction.test.ts +++ b/packages/memory-host-sdk/src/host/remote-error-redaction.test.ts @@ -147,7 +147,7 @@ describe.sequential("memory remote error redaction", () => { }).catch((cause: unknown) => cause); expect(error).toBeInstanceOf(Error); - expect((error as Error).message).toContain('{"Authorization":"bearer ***"}'); + expect((error as Error).message).toContain('{"Authorization":"***"}'); expect((error as Error).message).not.toContain(SHORT_API_KEY); expect(records.map((record) => record.authorization)).toEqual([`bearer ${SHORT_API_KEY}`]); } finally { @@ -217,7 +217,7 @@ describe.sequential("memory remote error redaction", () => { errorPrefix: "file upload failed", }).catch((cause: unknown) => cause); expect(shortError).toBeInstanceOf(Error); - expect((shortError as Error).message).toContain('{"Authorization":"bearer ***"}'); + expect((shortError as Error).message).toContain('{"Authorization":"***"}'); expect((shortError as Error).message).not.toContain(SHORT_API_KEY); await expect( diff --git a/packages/memory-host-sdk/src/host/remote-http.ts b/packages/memory-host-sdk/src/host/remote-http.ts index bc9d4b830f9f..88d387b12336 100644 --- a/packages/memory-host-sdk/src/host/remote-http.ts +++ b/packages/memory-host-sdk/src/host/remote-http.ts @@ -4,7 +4,7 @@ import { shouldUseEnvHttpProxyForUrl, ssrfPolicyFromHttpBaseUrlAllowedHostname, } from "./openclaw-runtime-network.js"; -import type { SsrFPolicy } from "./ssrf-policy.js"; +import type { SsrFPolicy } from "./openclaw-runtime-network.js"; // Remote memory HTTP wrapper that applies SSRF policy and releases guarded sockets. diff --git a/packages/memory-host-sdk/src/host/ssrf-policy.ts b/packages/memory-host-sdk/src/host/ssrf-policy.ts deleted file mode 100644 index 56de4c341d7f..000000000000 --- a/packages/memory-host-sdk/src/host/ssrf-policy.ts +++ /dev/null @@ -1,11 +0,0 @@ -// Public SSRF policy shape accepted by memory host remote HTTP helpers. - -/** Host/network allowlist policy forwarded to the runtime SSRF guard. */ -export type SsrFPolicy = { - allowPrivateNetwork?: boolean; - dangerouslyAllowPrivateNetwork?: boolean; - allowRfc2544BenchmarkRange?: boolean; - allowIpv6UniqueLocalRange?: boolean; - allowedHostnames?: string[]; - hostnameAllowlist?: string[]; -}; diff --git a/src/acp/control-plane/manager.utils.ts b/src/acp/control-plane/manager.utils.ts index 657e4b84dda6..34116665bcf2 100644 --- a/src/acp/control-plane/manager.utils.ts +++ b/src/acp/control-plane/manager.utils.ts @@ -1,5 +1,3 @@ -/** Shared ACP manager normalization, resolution, and error helpers. */ -import { ACP_ERROR_CODES, AcpRuntimeError } from "@openclaw/acp-core/runtime/errors"; import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce"; import { canonicalizeMainSessionAlias, @@ -13,6 +11,8 @@ import { normalizeMainKey, parseAgentSessionKey, } from "../../routing/session-key.js"; +/** Shared ACP manager normalization, resolution, and error helpers. */ +import { ACP_ERROR_CODES, AcpRuntimeError } from "../runtime/errors.js"; import type { AcpSessionResolution } from "./manager.types.js"; /** Resolves the agent id encoded in an ACP session key. */ diff --git a/src/acp/policy.ts b/src/acp/policy.ts index 5aa5b0adc815..9cdab4d7f12b 100644 --- a/src/acp/policy.ts +++ b/src/acp/policy.ts @@ -1,7 +1,7 @@ -/** Policy gates for ACP availability, dispatch, and allowed agent ids. */ -import { AcpRuntimeError } from "@openclaw/acp-core/runtime/errors"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import { normalizeAgentId } from "../routing/session-key.js"; +/** Policy gates for ACP availability, dispatch, and allowed agent ids. */ +import { AcpRuntimeError } from "./runtime/errors.js"; const ACP_DISABLED_MESSAGE = "ACP is disabled by policy (`acp.enabled=false`)."; const ACP_DISPATCH_DISABLED_MESSAGE = diff --git a/src/acp/runtime/errors.test.ts b/src/acp/runtime/errors.test.ts new file mode 100644 index 000000000000..6a30eeddda1f --- /dev/null +++ b/src/acp/runtime/errors.test.ts @@ -0,0 +1,45 @@ +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import { afterEach, describe, expect, it } from "vitest"; +import { withEnv } from "../../test-utils/env.js"; +import { AcpRuntimeError, formatAcpErrorChain } from "./errors.js"; + +let tempDirs: string[] = []; + +function writeConfig(source: string): string { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-acp-redact-config-")); + tempDirs.push(dir); + const configPath = path.join(dir, "openclaw.json"); + fs.writeFileSync(configPath, source); + return configPath; +} + +afterEach(() => { + for (const dir of tempDirs) { + fs.rmSync(dir, { force: true, recursive: true }); + } + tempDirs = []; +}); + +describe("ACP runtime error redaction", () => { + it("keeps provider-token coverage when operator redact patterns are configured", () => { + const configPath = writeConfig(`{ + logging: { + redactPatterns: ["/internal-ticket-([A-Za-z0-9]+)/g"], + }, + }`); + const providerToken = `ghp_${"a".repeat(20)}`; + const customSecret = "internal-ticket-12345"; + + const output = withEnv({ OPENCLAW_CONFIG_PATH: configPath }, () => + formatAcpErrorChain( + new AcpRuntimeError("ACP_TURN_FAILED", `backend failed: ${providerToken} ${customSecret}`), + ), + ); + + expect(output).not.toContain(providerToken); + expect(output).not.toContain(customSecret); + expect(output).toContain("backend failed"); + }); +}); diff --git a/src/acp/runtime/errors.ts b/src/acp/runtime/errors.ts index 12c03465abad..a261ba83b81a 100644 --- a/src/acp/runtime/errors.ts +++ b/src/acp/runtime/errors.ts @@ -1,8 +1,11 @@ /** ACP runtime error exports wired to OpenClaw secret redaction. */ import { configureAcpErrorRedactor } from "@openclaw/acp-core"; -import { redactSensitiveText } from "../../logging/redact.js"; +import { redactToolPayloadText } from "../../logging/redact.js"; -// Ensure ACP-core runtime errors use OpenClaw's secret redaction before re-export. -configureAcpErrorRedactor(redactSensitiveText); +// Core must import ACP errors and error text only through this barrel so the +// canonical redactor is configured first. It merges operator patterns with the +// defaults so custom logging policy cannot disable provider-token coverage. +configureAcpErrorRedactor(redactToolPayloadText); export * from "@openclaw/acp-core/runtime/errors"; +export * from "@openclaw/acp-core/runtime/error-text"; diff --git a/src/auto-reply/reply/commands-acp/diagnostics.ts b/src/auto-reply/reply/commands-acp/diagnostics.ts index 2ae528d78970..7a076f3f8a55 100644 --- a/src/auto-reply/reply/commands-acp/diagnostics.ts +++ b/src/auto-reply/reply/commands-acp/diagnostics.ts @@ -1,11 +1,10 @@ // Formats ACP diagnostics and runtime error details for command replies. -import { formatAcpRuntimeErrorText } from "@openclaw/acp-core/runtime/error-text"; import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, } from "@openclaw/normalization-core/string-coerce"; import { getAcpSessionManager } from "../../../acp/control-plane/manager.js"; -import { toAcpRuntimeError } from "../../../acp/runtime/errors.js"; +import { formatAcpRuntimeErrorText, toAcpRuntimeError } from "../../../acp/runtime/errors.js"; import { getAcpRuntimeBackend, requireAcpRuntimeBackend } from "../../../acp/runtime/registry.js"; import { listAcpSessionEntries, readAcpSessionEntry } from "../../../acp/runtime/session-meta.js"; import type { SessionEntry } from "../../../config/sessions/types.js"; diff --git a/src/auto-reply/reply/commands-acp/shared.ts b/src/auto-reply/reply/commands-acp/shared.ts index aeb2ee0bfe74..8773105b7af4 100644 --- a/src/auto-reply/reply/commands-acp/shared.ts +++ b/src/auto-reply/reply/commands-acp/shared.ts @@ -1,13 +1,12 @@ // Shared ACP command helpers for session identity and reply formatting. import { randomUUID } from "node:crypto"; -import { toAcpRuntimeErrorText } from "@openclaw/acp-core/runtime/error-text"; import type { AcpRuntimeSessionMode } from "@openclaw/acp-core/runtime/types"; import type { Result } from "@openclaw/normalization-core/result"; import { normalizeOptionalLowercaseString, normalizeOptionalString, } from "@openclaw/normalization-core/string-coerce"; -import type { AcpRuntimeError } from "../../../acp/runtime/errors.js"; +import { type AcpRuntimeError, toAcpRuntimeErrorText } from "../../../acp/runtime/errors.js"; import { supportsAutomaticThreadBindingSpawn } from "../../../channels/thread-bindings-policy.js"; import type { AcpSessionRuntimeOptions } from "../../../config/sessions/types.js"; import { normalizeAgentId } from "../../../routing/session-key.js"; diff --git a/src/auto-reply/reply/dispatch-acp.ts b/src/auto-reply/reply/dispatch-acp.ts index a50347befe46..85b89fff5c35 100644 --- a/src/auto-reply/reply/dispatch-acp.ts +++ b/src/auto-reply/reply/dispatch-acp.ts @@ -1,5 +1,4 @@ // Dispatches reply turns through ACP runtimes and projects their events. -import { formatAcpRuntimeErrorText } from "@openclaw/acp-core/runtime/error-text"; import { resolveAcpThreadSessionDetailLines } from "@openclaw/acp-core/runtime/session-identifiers"; import { isSessionIdentityPending, @@ -12,7 +11,11 @@ import { } from "@openclaw/normalization-core/string-coerce"; import type { AcpTurnAttachment } from "../../acp/control-plane/manager.types.js"; import { resolveAcpAgentPolicyError, resolveAcpDispatchPolicyError } from "../../acp/policy.js"; -import { AcpRuntimeError, toAcpRuntimeError } from "../../acp/runtime/errors.js"; +import { + AcpRuntimeError, + formatAcpRuntimeErrorText, + toAcpRuntimeError, +} from "../../acp/runtime/errors.js"; import { resolveAgentDir, resolveAgentWorkspaceDir } from "../../agents/agent-scope.js"; import { toolPolicyRestrictsTools } from "../../agents/tool-policy.js"; import type { ChatType } from "../../channels/chat-type.js"; diff --git a/src/plugins/contracts/extension-package-project-boundaries.test.ts b/src/plugins/contracts/extension-package-project-boundaries.test.ts index 357fd1657def..9da6e78700a2 100644 --- a/src/plugins/contracts/extension-package-project-boundaries.test.ts +++ b/src/plugins/contracts/extension-package-project-boundaries.test.ts @@ -57,6 +57,7 @@ const MEMORY_HOST_SDK_EXPORTS = [ "./status", ] as const; const MEMORY_HOST_SDK_ALLOWED_CORE_BRIDGE_FILES = [ + "packages/memory-host-sdk/src/host/error-utils.ts", "packages/memory-host-sdk/src/host/openclaw-runtime-auth.ts", "packages/memory-host-sdk/src/host/openclaw-runtime-kysely.ts", "packages/memory-host-sdk/src/host/openclaw-runtime-network.ts",