mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
feat(secrets): agent-requested credentials the model never sees (#129670)
* feat(secrets): agent-requested credentials the model never sees The new main-session secrets tool lets the agent request a credential by name: the human enters the value in a masked question card (Control UI, /ask/<id> deep link, iOS/macOS/Android), and the gateway diverts the answer straight into the shared secret store at question.resolve. The record, broadcast, waitAnswer, tool result, transcript, and model context only ever carry a synthetic stored marker. - protocol: additive secretStore binding, secretStoreExisting replacement metadata, and resolve-time secretStoreAllowedHosts (since 2026.8) - gateway: store-bound question validation, admin-gated minting (blocks questions-scope self-answer escalation past secrets.store.set), shared redaction-first store write service reused by secrets.store.set - tool: secrets request/list/delete; write-only by design, delete carries verified agent runtime identity; channel delivery is link-only so chat text is never captured as a secret - Control UI: masked composer card with requester identity, store banner, editable allowed hosts, replacement warning, retry-on-validation-error, a standalone /ask/<id> page, and a named startup-JS baseline bump - mobile: SecureField / password transformation for isSecret questions, no answer echo in terminal summaries; new native string registered in the locale-refresh inventory (generated artifacts stay workflow-owned) - regression: claimed harness secret input stays out of session transcripts Live-proven on an isolated dev gateway: real model turn, masked entry via Playwright, value present only in secret_store_entries, absent from every transcript, log, and the DOM. * chore(protocol): regenerate protocol models and tool display * fix(cli): read image string options through a typed helper PR #129463 added four commander option narrowings in image.ts without SAFETY coverage, leaving the assertion-safety ratchet red (21 > 17) for every branch on current main. Replace the casts with a typeof-checked read so the assertions are removed rather than annotated; each value is still validated by its normalizer. SAFETY comments cannot work in this file: the ratchet's raw scanner never rescans template tokens, so comments after the first substitution template are unreadable to it. * chore(protocol): refresh Swift models against current main * chore(i18n): re-baseline the native inventory on current main * docs(secrets): state the default-on tool policy and how to disable it * fix(secrets): tell the model what the store actually does The shipped tool description named the three actions and nothing else, and no parameter carried a description. The model could not tell that request blocks a human, that reason is shown to that human, what secret and env select, or - the silent-failure case - that a secret stored with no allowedHosts can never be substituted, so a successful request could produce a permanently unusable credential. Move the description to the presets module beside ask_user and document every parameter. * refactor(agents): share one blocking-question lifecycle between tools ask_user and secrets each carried their own registration, wait, and cancel logic, and they had diverged: ask_user recovers an answer that lands between its wait timeout and the cancel, while secrets discarded it and reported no_answer even though the Gateway had already stored the credential. One shared canceller and answer reader fixes that race for both, folds the two divergent gateway-call types into one, and drops two type assertions in favour of the canonical record guard (ask_user's assertion baseline shrinks 11 -> 8). Net +49 production lines: the shared module costs more than the duplication it removes, and buys the correctness fix plus a single owner for question lifecycle. * fix(ui): keep the allowed-hosts field readable as an input Main's composer restructure moved the free-text input styling into the option-row context, so the store-request hosts field - which sits outside a row - lost its border and read as static text. It is the one field the operator is meant to review and edit before releasing a credential, so give it its own border and focus ring. * fix(secrets): close two credential-boundary holes in agent requests Requests are now protected-secret only. list renders env values, so an agent could request kind=env, watch a human type it into a masked box under a no-visibility promise, then read it straight back; the tool text even claimed values are never returned. Environment values stay operator -set in Settings or the CLI, where they are agent-readable by design. Store-bound questions are also bound to the run that requested them. The resolve path authorized only the answering client, so a terminated or replaced agent run could still have a credential written on its behalf - the recorded runId was provenance, not closure-bound authority. Minting now requires a runId and resolution revalidates that exact live run immediately before the store write, with no await in between, failing closed as QUESTION_REQUESTER_INACTIVE. Both reported by ClawSweeper as P1 credential-boundary findings.
This commit is contained in:
committed by
GitHub
parent
30487606d1
commit
ef95d8f55e
@@ -1409,6 +1409,7 @@
|
||||
"tools/music-generation",
|
||||
"tools/pdf",
|
||||
"tools/reactions",
|
||||
"tools/secrets",
|
||||
"tools/thinking",
|
||||
"tools/tokenjuice",
|
||||
"tools/tool-search",
|
||||
|
||||
Reference in New Issue
Block a user