Repository navigation
Commit 60e1d94
Add credential fill, vaults, TOTP and 1Password tokens, with LLM tools (#142)
* Add website credentials and session credential fill
Credentials are secrets of type "credential" whose value maps field names
to strings. The value is checked locally, serialized as compact UTF-8 JSON
and sealed with the encryption context the API returns, like any secret.
- Secret gains type and metadata (browser.allowedOrigins); create accepts
type, metadata and a mapping value; list filters by type; update sends
metadata with null kept, so a member can be cleared.
- secrets.create_credential() and secrets.set_allowed_origins().
- add_version() checks the value's shape against the secret's type.
- sessions.create() takes credentials; the session lists attached ones.
- sessions.credentials.fill() validates the request locally and posts it
with a timeout of at least 30 seconds.
- A str secret value that isn't valid UTF-8 (a lone surrogate) now raises
invalid_secret_value instead of UnicodeEncodeError.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Add a fill_credential LLM tool and Gemini tool declarations
CredentialFillTool exposes sessions.credentials.fill() to a model with
the session ID bound by the application. The model picks the credential
by name, the fields and their selectors, and optionally a page ID or an
iframe URL; it never sees values. runnable() and async_runnable() return
the fill result as compact JSON, or the error's code, message,
retryable flag and server details as JSON so the model can react, for
example by choosing a page after CREDENTIAL_PAGE_AMBIGUOUS.
The definitions come for OpenAI (strict), Anthropic and Gemini. Gemini
schemas are an OpenAPI subset, so tools/gemini.py converts the JSON
schemas (nullable instead of a null type, no additionalProperties), and
every existing tool gains a gemini_tool_definition too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Document credential fill and the LLM tools
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Parse secret types the API adds later, and update README models
Secret.type is now a str defaulting to "secret", so a new type doesn't
break list() or get(). Requests still accept only the known SecretType
values. The README's LLM samples use gpt-5, claude-sonnet-5-5 and
gemini-3.5-flash.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Bump the version to 1.13.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FzcEMZLVjoiueoQFxG6F7S
* Correct the browser sessions scope and SECRET_TYPE_MISMATCH status in the README
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FzcEMZLVjoiueoQFxG6F7S
* Leave the version for the release to set
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FzcEMZLVjoiueoQFxG6F7S
* List credential fill events in session event logs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dbwbLvQGyzwkxNetvqf3v
* Fill secrets and vaults, and add TOTP and op_token secrets
The credential secret type is gone: a secret is fillable once it has
allowed origins, and a login is usually several secrets grouped in a
vault. Secrets take type totp (checked locally as the platform reads
seeds) or op_token, and allowed_origins on create. client.vaults manages
stored and 1Password vaults; sandboxes and processes take vault next to
secrets, and report each binding's source, type and 1Password reference.
Sessions attach secrets or vaults, fills take credential or vault with
page_url, and fill_credential lets a model choose either.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dbwbLvQGyzwkxNetvqf3v
* Document vaults, TOTP and 1Password secrets, and fill by vault
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dbwbLvQGyzwkxNetvqf3v
* Name VAULT_ENTRY_INVALID for entries of the wrong kind in the README
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dbwbLvQGyzwkxNetvqf3v
* Read TOTP seeds as vm-service does, and refuse non-object tool input
Strip one leading BOM, then Go's whitespace; uppercase per character so
ß and ff don't become base32; refuse stray % outside the query, trailing
newlines in digits or period, and malformed userinfo; accept userinfo
before totp as Go does; read query pairs as Go's ParseQuery. The fill
tool answers input that isn't an object with an invalid_request error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dbwbLvQGyzwkxNetvqf3v
* Document SECRET_TOTP_UNSUPPORTED as 501
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dbwbLvQGyzwkxNetvqf3v
* Document SECRET_ONEPASSWORD_UNSUPPORTED as 501
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dbwbLvQGyzwkxNetvqf3v
* Drop TOTP as the example of a value a host can't fill
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dbwbLvQGyzwkxNetvqf3v
* Take 1Password fields per request instead of linking vaults
browserctrl #1552 no longer links vaults to 1Password: vaults hold stored
secrets only, and 1Password fields are named per request with onePassword
on sandbox create and process start.
- Vaults: drop source and the 1Password entry, source and token models.
Entries are StoredEntry(name, version), reported as VaultEntry, and None
in an update removes one. Create and update params refuse unknown members
such as a leftover source; a source in a response is ignored.
- Sandboxes: one_password=OnePasswordSource(token, vault, fields) on create
(image launches), exec and start, sync and async, sent as onePassword.
Token and env names, part rules (UTF-16 length, no '/', '?', Cc, Cf, Zl
or Zp, not '.' or '..'), field queries, the 512-byte reference, 1-32
fields, strict members, and clashes with secrets or env are all checked
before any request. A clash with the vault is left to the server.
- Bindings document source type "onePassword" with reference and
token_secret.
- README: one_password examples and rules, stored-only vaults, and the
error codes without VAULT_ENTRY_INVALID and VAULT_SOURCE_INVALID.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dbwbLvQGyzwkxNetvqf3v
* Explain how a fill chooses its tab, with the origin check after
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dbwbLvQGyzwkxNetvqf3v
* Fill 1Password fields into browser sessions through an op_token
Sessions attach an op_token with credentials=[{"one_password": name}],
sent as {"onePassword": name}. sessions.credentials.fill() takes
one_password={"token", "vault", "allowed_origins"} with a ref
{"item", "section"?, "field"} on every field, sent as onePassword /
allowedOrigins, and checks it all locally as #1552 does. Results gain
each field's op:// reference; the top-level version stays optional.
Allowed origins are now checked locally as the server normalizes them,
for secrets (create, update, set_allowed_origins) and for 1Password
fills alike. fill_credential stays without 1Password: a model must not
choose the origins its values may be typed on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dbwbLvQGyzwkxNetvqf3v
* Read TOTP seeds split across lines, as vm-service now does
#1573's vm-service drops CR and LF from a seed with its spaces and hyphens
before the length check (its base32 decoder skips them), so a seed pasted
across lines is valid. The clients refused it; they now drop them too. A raw
line break inside an otpauth URI is still refused, as Go's url.Parse does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dbwbLvQGyzwkxNetvqf3v
* Check origins and secret env names as master does
Allowed origins are trimmed the way JavaScript's trim() does, so a
leading byte-order mark is accepted and \x1c-\x1f or \x85 are not, and an
IPv6 zone is checked as Node's isIPv6 does, which Python 3.8 refused
outright. A `secrets` variable name longer than 256 characters is now
refused locally, as the server refuses it.
The README now says a frame fill skips the allowed-origin tab step, that
SECRET_ONEPASSWORD_AUTH_FAILED also covers a malformed token or one for
another sign-in host, and the 503 that CREDENTIAL_FILL_FAILED and
SECRET_ONEPASSWORD_FAILED can carry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dbwbLvQGyzwkxNetvqf3v
* Accept tab_opened session events
The API has sent tab_opened events since browserctrl #559, and the event
type Literal refused them, so listing such a session's events failed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dbwbLvQGyzwkxNetvqf3v
* Simplify credential validation and keep Gemini tools scoped to fill
* Bump the version to 1.13.1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>1 parent c638258 commit 60e1d94
49 files changed
Lines changed: 4738 additions & 111 deletions
File tree
- docs
- hyperbrowser
- client
- managers
- async_manager
- sandboxes
- sandboxes
- sync_manager
- sandboxes
- models
- tools
- types
- tests
- typecheck
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
| 55 | + | |
| 56 | + | |
55 | 57 | | |
56 | 58 | | |
57 | 59 | | |
| |||
69 | 71 | | |
70 | 72 | | |
71 | 73 | | |
72 | | - | |
73 | | - | |
| 74 | + | |
| 75 | + | |
74 | 76 | | |
| 77 | + | |
75 | 78 | | |
76 | 79 | | |
77 | 80 | | |
| |||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
| |||
51 | 52 | | |
52 | 53 | | |
53 | 54 | | |
| 55 | + | |
54 | 56 | | |
55 | 57 | | |
56 | 58 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
| |||
79 | 80 | | |
80 | 81 | | |
81 | 82 | | |
| 83 | + | |
82 | 84 | | |
83 | 85 | | |
84 | 86 | | |
| |||
145 | 147 | | |
146 | 148 | | |
147 | 149 | | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
148 | 154 | | |
149 | 155 | | |
150 | 156 | | |
| |||
331 | 337 | | |
332 | 338 | | |
333 | 339 | | |
| 340 | + | |
| 341 | + | |
334 | 342 | | |
335 | 343 | | |
336 | 344 | | |
337 | 345 | | |
338 | | - | |
339 | | - | |
340 | | - | |
341 | | - | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
342 | 354 | | |
343 | 355 | | |
344 | 356 | | |
| |||
349 | 361 | | |
350 | 362 | | |
351 | 363 | | |
| 364 | + | |
| 365 | + | |
352 | 366 | | |
353 | 367 | | |
354 | 368 | | |
| |||
1178 | 1192 | | |
1179 | 1193 | | |
1180 | 1194 | | |
| 1195 | + | |
| 1196 | + | |
| 1197 | + | |
| 1198 | + | |
| 1199 | + | |
1181 | 1200 | | |
1182 | 1201 | | |
1183 | 1202 | | |
1184 | | - | |
1185 | | - | |
| 1203 | + | |
| 1204 | + | |
| 1205 | + | |
| 1206 | + | |
1186 | 1207 | | |
1187 | 1208 | | |
1188 | 1209 | | |
1189 | 1210 | | |
1190 | | - | |
| 1211 | + | |
1191 | 1212 | | |
1192 | 1213 | | |
1193 | 1214 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| 29 | + | |
29 | 30 | | |
30 | 31 | | |
31 | 32 | | |
| |||
354 | 355 | | |
355 | 356 | | |
356 | 357 | | |
| 358 | + | |
| 359 | + | |
357 | 360 | | |
358 | 361 | | |
359 | 362 | | |
| |||
364 | 367 | | |
365 | 368 | | |
366 | 369 | | |
| 370 | + | |
| 371 | + | |
367 | 372 | | |
368 | 373 | | |
369 | 374 | | |
| |||
383 | 388 | | |
384 | 389 | | |
385 | 390 | | |
| 391 | + | |
| 392 | + | |
386 | 393 | | |
387 | 394 | | |
388 | 395 | | |
389 | | - | |
390 | | - | |
391 | | - | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
392 | 402 | | |
393 | 403 | | |
394 | 404 | | |
| |||
399 | 409 | | |
400 | 410 | | |
401 | 411 | | |
| 412 | + | |
| 413 | + | |
402 | 414 | | |
403 | | - | |
| 415 | + | |
404 | 416 | | |
405 | 417 | | |
406 | 418 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
| 2 | + | |
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
26 | 27 | | |
27 | 28 | | |
28 | 29 | | |
| 30 | + | |
29 | 31 | | |
30 | 32 | | |
31 | 33 | | |
32 | 34 | | |
33 | | - | |
| 35 | + | |
34 | 36 | | |
| 37 | + | |
35 | 38 | | |
36 | 39 | | |
37 | 40 | | |
| |||
72 | 75 | | |
73 | 76 | | |
74 | 77 | | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
75 | 83 | | |
76 | 84 | | |
77 | 85 | | |
78 | 86 | | |
79 | | - | |
| 87 | + | |
80 | 88 | | |
81 | | - | |
82 | | - | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
83 | 93 | | |
84 | 94 | | |
85 | 95 | | |
| |||
88 | 98 | | |
89 | 99 | | |
90 | 100 | | |
91 | | - | |
| 101 | + | |
92 | 102 | | |
93 | 103 | | |
94 | | - | |
| 104 | + | |
95 | 105 | | |
96 | 106 | | |
97 | 107 | | |
| |||
107 | 117 | | |
108 | 118 | | |
109 | 119 | | |
110 | | - | |
111 | | - | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | | - | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
116 | 128 | | |
117 | 129 | | |
118 | | - | |
119 | | - | |
120 | | - | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
121 | 146 | | |
| 147 | + | |
122 | 148 | | |
123 | | - | |
| 149 | + | |
124 | 150 | | |
125 | 151 | | |
126 | 152 | | |
| |||
143 | 169 | | |
144 | 170 | | |
145 | 171 | | |
146 | | - | |
| 172 | + | |
147 | 173 | | |
148 | | - | |
| 174 | + | |
| 175 | + | |
149 | 176 | | |
150 | 177 | | |
151 | 178 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
| |||
71 | 72 | | |
72 | 73 | | |
73 | 74 | | |
| 75 | + | |
74 | 76 | | |
75 | 77 | | |
76 | 78 | | |
| |||
0 commit comments