ruby_llm-browser 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +61 -0
- data/CODE_OF_CONDUCT.md +11 -0
- data/CONTRIBUTING.md +42 -0
- data/LICENSE.txt +21 -0
- data/NOTICE.md +92 -0
- data/README.md +139 -0
- data/SECURITY.md +46 -0
- data/docs/API.md +177 -0
- data/docs/CNAME +1 -0
- data/docs/RAILS.md +167 -0
- data/docs/README.md +16 -0
- data/docs/RELEASE_ACTION_PLAN.md +81 -0
- data/docs/RELEASE_AUDIT.md +158 -0
- data/docs/RELEASING.md +131 -0
- data/docs/SECURITY_MODEL.md +117 -0
- data/docs/SPEC_BASELINE.md +107 -0
- data/docs/WORK.md +260 -0
- data/docs/_advanced/live-backend-qualification.md +74 -0
- data/docs/_advanced/rails-integration.md +56 -0
- data/docs/_config.yml +109 -0
- data/docs/_core_features/inspect-extract.md +91 -0
- data/docs/_core_features/offline-act.md +110 -0
- data/docs/_core_features/operation-lifecycle.md +63 -0
- data/docs/_core_features/source-policy.md +61 -0
- data/docs/_data/navigation.yml +12 -0
- data/docs/_data/sidebar.yml +8 -0
- data/docs/_data/social_links.yml +3 -0
- data/docs/_getting_started/configuration.md +68 -0
- data/docs/_getting_started/getting-started.md +77 -0
- data/docs/_getting_started/overview.md +52 -0
- data/docs/_plugins/versioned_docs.rb +46 -0
- data/docs/_reference/api-reference.md +29 -0
- data/docs/_reference/release-history.md +23 -0
- data/docs/_reference/upgrading.md +33 -0
- data/docs/bin/build-api.sh +23 -0
- data/docs/bin/build.sh +161 -0
- data/docs/bin/export-api-markdown.rb +53 -0
- data/docs/bin/link_versions.rb +54 -0
- data/docs/bin/postprocess_api_seo.rb +129 -0
- data/docs/bin/prepare_versions.rb +40 -0
- data/docs/bin/serve.sh +12 -0
- data/docs/bin/versions.yml +14 -0
- data/docs/index.md +82 -0
- data/examples/plain_ruby.rb +34 -0
- data/examples/rails_adapter.rb +47 -0
- data/lib/generators/ruby_llm/browser/install_generator.rb +29 -0
- data/lib/generators/ruby_llm/browser/templates/create_ruby_llm_browser_tables.rb.tt +60 -0
- data/lib/ruby_llm/browser/approval.rb +128 -0
- data/lib/ruby_llm/browser/approval_store.rb +38 -0
- data/lib/ruby_llm/browser/backend.rb +99 -0
- data/lib/ruby_llm/browser/budget.rb +90 -0
- data/lib/ruby_llm/browser/capabilities.rb +76 -0
- data/lib/ruby_llm/browser/configuration.rb +74 -0
- data/lib/ruby_llm/browser/context.rb +117 -0
- data/lib/ruby_llm/browser/doctor.rb +134 -0
- data/lib/ruby_llm/browser/engine.rb +326 -0
- data/lib/ruby_llm/browser/errors.rb +86 -0
- data/lib/ruby_llm/browser/fake_backend.rb +134 -0
- data/lib/ruby_llm/browser/immutable.rb +19 -0
- data/lib/ruby_llm/browser/in_memory_approval_store.rb +67 -0
- data/lib/ruby_llm/browser/in_memory_operation_store.rb +174 -0
- data/lib/ruby_llm/browser/operation.rb +218 -0
- data/lib/ruby_llm/browser/operation_store.rb +92 -0
- data/lib/ruby_llm/browser/policy.rb +298 -0
- data/lib/ruby_llm/browser/rails/active_record_approval_store.rb +72 -0
- data/lib/ruby_llm/browser/rails/active_record_operation_store.rb +231 -0
- data/lib/ruby_llm/browser/rails/actor_record.rb +13 -0
- data/lib/ruby_llm/browser/rails/approval_record.rb +49 -0
- data/lib/ruby_llm/browser/rails/operation_job.rb +163 -0
- data/lib/ruby_llm/browser/rails/operation_record.rb +56 -0
- data/lib/ruby_llm/browser/rails/reaper.rb +117 -0
- data/lib/ruby_llm/browser/rails/schema.rb +81 -0
- data/lib/ruby_llm/browser/rails.rb +79 -0
- data/lib/ruby_llm/browser/redactor.rb +159 -0
- data/lib/ruby_llm/browser/result.rb +102 -0
- data/lib/ruby_llm/browser/stagehand_backend.rb +332 -0
- data/lib/ruby_llm/browser/tool.rb +70 -0
- data/lib/ruby_llm/browser/tools/act.rb +91 -0
- data/lib/ruby_llm/browser/tools/extract.rb +60 -0
- data/lib/ruby_llm/browser/tools/inspect.rb +38 -0
- data/lib/ruby_llm/browser/url_guard.rb +253 -0
- data/lib/ruby_llm/browser/version.rb +9 -0
- data/lib/ruby_llm/browser.rb +79 -0
- metadata +267 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Security Model
|
|
4
|
+
description: Understand what the gem enforces and what a deployment must prove independently.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Security model
|
|
8
|
+
|
|
9
|
+
Understand what the gem enforces and what a deployment must prove independently.
|
|
10
|
+
|
|
11
|
+
After reading this guide, you will know:
|
|
12
|
+
|
|
13
|
+
- Which inputs are trusted.
|
|
14
|
+
- Why local URL validation does not secure a remote browser.
|
|
15
|
+
- How sessions, cancellation, unknown outcomes, and secrets are handled.
|
|
16
|
+
|
|
17
|
+
## Trust boundaries
|
|
18
|
+
|
|
19
|
+
The host owns authentication, actor/run authorization, consent, provider configuration,
|
|
20
|
+
source grants, budgets and approval issuance. The model, browser page and provider
|
|
21
|
+
payload are untrusted. A `Context` expresses a host decision; it does not authenticate
|
|
22
|
+
that decision. Unscoped store APIs are for trusted workers, not public controllers.
|
|
23
|
+
|
|
24
|
+
## Destinations and egress
|
|
25
|
+
|
|
26
|
+
URL validation rejects unsupported schemes/ports, userinfo, ambiguous numeric IP forms,
|
|
27
|
+
unapproved hosts, and local/private/link-local/metadata/reserved IP answers, including
|
|
28
|
+
IPv6 and IPv4-mapped addresses. Real DNS validation is enabled by default.
|
|
29
|
+
|
|
30
|
+
These checks run in Ruby. They do **not** enforce a remote browser's DNS view, redirects,
|
|
31
|
+
iframes, popups, WebSockets, subresources, scripts or connection-time rebinding.
|
|
32
|
+
`Policy#authorize_egress!` refuses an unverified backend before starting a session. The
|
|
33
|
+
built-in `StagehandBackend` always reports unverified egress and is unsupported for live
|
|
34
|
+
operations in the first release. No constructor option can change that. A custom backend
|
|
35
|
+
must enforce and evidence its own browser-side egress controls.
|
|
36
|
+
|
|
37
|
+
Before a host makes that assertion, it must test every request path against a controlled
|
|
38
|
+
public test origin and prove private/metadata addresses remain unreachable at connection
|
|
39
|
+
time. Asset origins must be explicitly approved by the network layer. Also qualify
|
|
40
|
+
local-mode browsers; a local browser is not a sandbox by default.
|
|
41
|
+
|
|
42
|
+
Stagehand navigation results may be null. The adapter refuses to invent a final URL in
|
|
43
|
+
that case. A live deployment must establish how its actual server reports a verified
|
|
44
|
+
current URL; the SDK schema alone is not evidence. The current release has no supported
|
|
45
|
+
Stagehand deployment. Returned page data remains untrusted.
|
|
46
|
+
|
|
47
|
+
## Operation identity and recovery
|
|
48
|
+
|
|
49
|
+
- Reserve operation identity and actor quota before start. Claim reserved-to-starting
|
|
50
|
+
atomically, checking the exact fence. A duplicate job cannot start a second session.
|
|
51
|
+
- Rails idempotency keys bind the exact payload and budget. Per-actor write-lock rows
|
|
52
|
+
serialize even the first two reservations when there are no open operation rows.
|
|
53
|
+
- Persist returned session identity before further calls, including a return that races
|
|
54
|
+
with cancellation. A persistence exception still triggers a cleanup attempt.
|
|
55
|
+
- Disable SDK retries at client and request levels. The SDK's idempotency option is not
|
|
56
|
+
treated as a provider guarantee: its client has no configured idempotency header.
|
|
57
|
+
- Cancellation cannot undo a dispatched request. It fences stale workers and holds quota
|
|
58
|
+
in `cleanup_pending` until provider-confirmed closure. A never-started reservation can
|
|
59
|
+
become terminal immediately.
|
|
60
|
+
- A reaper fences before reconciliation/cleanup. It attempts to close known session IDs
|
|
61
|
+
even if reconciliation is unavailable. Database/provider failures never count as
|
|
62
|
+
successful cleanup. A local deadline or idle TTL is not proof of provider expiry.
|
|
63
|
+
- A start whose session ID is unknown cannot be automatically reconciled by the current
|
|
64
|
+
Stagehand adapter. Hold quota and escalate to host/provider review. Never start a new
|
|
65
|
+
operation merely to conceal or retry an uncertain outcome.
|
|
66
|
+
|
|
67
|
+
SQLite concurrency is tested with independent connections. PostgreSQL remains untested
|
|
68
|
+
in this audit. A global reaper must use the same backend configuration as the operations
|
|
69
|
+
it sees; multi-backend routing is not represented in the schema.
|
|
70
|
+
|
|
71
|
+
## Actions and approvals
|
|
72
|
+
|
|
73
|
+
**Live Act is disabled at the Engine boundary**, including when a backend advertises
|
|
74
|
+
action support. The first release is read-only; the full live Act protocol is deferred to
|
|
75
|
+
a later version. Offline simulation checks RubyLLM approval integration, read-only grant
|
|
76
|
+
resolution, atomic single-use consumption, actor/run/action/URL and supplied revision
|
|
77
|
+
bindings, expiration, revocation, replay, and unknown dispatch outcomes.
|
|
78
|
+
|
|
79
|
+
That is not the complete production protocol: operation/session/page bindings are
|
|
80
|
+
optional on the current Approval object; a candidate-action hash is not a DOM/target
|
|
81
|
+
revision; and each Engine call starts a new session. Implement and verify same-session
|
|
82
|
+
host approval and fresh target/policy checks before enabling live Act.
|
|
83
|
+
|
|
84
|
+
Keyword filters on selectors/descriptions cannot prove semantic safety. An innocuously
|
|
85
|
+
named button can purchase or publish. They are only defense in depth. Purchases,
|
|
86
|
+
posting, account changes, credentials and access-control bypass remain unsupported.
|
|
87
|
+
|
|
88
|
+
## Output, schema, and secret handling
|
|
89
|
+
|
|
90
|
+
Extraction data is validated against the host schema before redaction/truncation. Model
|
|
91
|
+
byte requests cannot increase policy ceilings. The retained serialized JSON fits both
|
|
92
|
+
the policy ceiling and remaining operation bytes, including UTF-8 and escaped text.
|
|
93
|
+
These limits do not cap remote browser bandwidth or provider response allocation.
|
|
94
|
+
|
|
95
|
+
The redactor removes credential-like fields, known credential literals and WebSocket
|
|
96
|
+
DevTools endpoints. URL provenance removes userinfo, fragments and credential-like
|
|
97
|
+
query values. Error messages do not include raw SDK bodies or parser input. Progress
|
|
98
|
+
messages contain no raw URL/selector. Active Job argument logging is disabled.
|
|
99
|
+
|
|
100
|
+
This is **not a general secret or PII detector**. Arbitrary page secrets, screenshots,
|
|
101
|
+
credentials under innocuous names and secrets not supplied to the redactor cannot be
|
|
102
|
+
reliably identified. Do not browse authenticated/private content; do not put credentials
|
|
103
|
+
in URLs or instructions; prevent host/RubyLLM/HTTP debug logging from recording payloads.
|
|
104
|
+
Queue data and approval action arguments may persist in the host database; encrypt,
|
|
105
|
+
scope and retain them appropriately. No browser cookies/profiles are supplied for reuse.
|
|
106
|
+
|
|
107
|
+
The adapter passes explicit SDK credentials/base URL and rejects unapproved custom
|
|
108
|
+
headers. Changes to relevant process environment values invalidate qualification.
|
|
109
|
+
Environment injection is for diagnostics/tests; the real SDK reads actual process ENV.
|
|
110
|
+
Do not mutate ENV during concurrent browser work. Session requests disable self-healing,
|
|
111
|
+
CAPTCHA solving and provider recording/logging; actual provider behavior still needs
|
|
112
|
+
qualification. Cleanup and TTL are best-effort, and cost values are advisory.
|
|
113
|
+
|
|
114
|
+
## Next steps
|
|
115
|
+
|
|
116
|
+
- Follow [Rails recovery]({% link RAILS.md %}) to schedule cleanup and protect status access.
|
|
117
|
+
- Review [the release audit]({% link RELEASE_AUDIT.md %}) for evidence and remaining blockers.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Specification Baseline and Provenance
|
|
4
|
+
description: Record product intent, evidence sources, and project ownership boundaries.
|
|
5
|
+
llms: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Specification baseline and provenance
|
|
9
|
+
|
|
10
|
+
This repository is the independent implementation of the `ruby_llm-browser` Gem. It is
|
|
11
|
+
the source of truth for code, tests and the WORK ledger. The product intent lives in a
|
|
12
|
+
separate specifications repository; this file records exactly which baseline was used.
|
|
13
|
+
|
|
14
|
+
## Baseline
|
|
15
|
+
|
|
16
|
+
| Field | Value |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| Intent source repository | `yorzi/oddlyniche`, folder `ruby-llm-browser` |
|
|
19
|
+
| Reviewed candidate Q | `22d488987517b10dcd96d2713ed3d47e8818b36b` |
|
|
20
|
+
| H2 approval/content commit C | `678f9faed6dfdd8e55a7c54566f94cfa1ad1bc0a` |
|
|
21
|
+
| Registration commit R | Pending; not registered |
|
|
22
|
+
| Source commit date | 2026-10-18 |
|
|
23
|
+
| Approved Specs candidate version at Q | `0.3.0-draft` (historical label; unchanged) |
|
|
24
|
+
| Implementation and gem release version | `0.1.0` (owner-selected 2026-10-18) |
|
|
25
|
+
| Spec lifecycle | `HANDOFF_READY`; independent H1 complete and owner H2 approved for exact Q |
|
|
26
|
+
| Implementation authorized | 2026-10-17; H2 handoff approved 2026-10-18 |
|
|
27
|
+
| RubyGems publication | Owner instructed release of `0.1.0` on 2026-10-18; this later instruction is separate from H2 |
|
|
28
|
+
| Gem | `ruby_llm-browser` |
|
|
29
|
+
| Namespace | `RubyLLM::Browser` |
|
|
30
|
+
| Require path | `ruby_llm/browser` |
|
|
31
|
+
| Working repository | `yorzi/ruby_llm-browser` |
|
|
32
|
+
|
|
33
|
+
## Pinned upstream facts used (source-read at the spec baseline)
|
|
34
|
+
|
|
35
|
+
| Dependency | Pin | Notes |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| Stagehand Ruby SDK | `stagehand` 3.21.0, tag `v3.21.0` (`b389c6e`) | Ruby `>= 3.2`; REST client, not a sandbox |
|
|
38
|
+
| RubyLLM | 2.0.0 and 2.1.1 | `Chat#with_tools` accepts Tool instances; `requires_approval` since 2.0; `progress`/`defer` since 2.1 |
|
|
39
|
+
|
|
40
|
+
## S0 decisions recorded here
|
|
41
|
+
|
|
42
|
+
1. **Hooks:** `Tool#progress` and `Tool.defer` exist only in RubyLLM 2.1+. This Gem
|
|
43
|
+
**feature-detects** them instead of raising the gemspec floor to `>= 2.1`, so the
|
|
44
|
+
supported floor stays `>= 2.0, < 3` (matching the 2.0.0 / 2.1.x matrix).
|
|
45
|
+
2. **Stagehand dependency:** declared as a runtime dependency (`~> 3.21`) for the
|
|
46
|
+
experimental adapter and cleanup path, but **required lazily** so requiring the Gem
|
|
47
|
+
never reads `STAGEHAND_*`/`BROWSERBASE_*`/`MODEL_API_KEY` environment variables or
|
|
48
|
+
triggers the SDK's local-server binary download. The adapter is unsupported for live
|
|
49
|
+
operations in the first release.
|
|
50
|
+
3. **Rails:** optional, loaded only via `require "ruby_llm/browser/rails"`.
|
|
51
|
+
4. **Frame and lib style:** explicit `require_relative` chain (no Zeitwerk loader) so the
|
|
52
|
+
load graph is fully predictable and the no-Rails guarantee is easy to prove.
|
|
53
|
+
|
|
54
|
+
## Audit corrections (2026-10-18)
|
|
55
|
+
|
|
56
|
+
- Restrict Stagehand to `~> 3.21.0`, not all future 3.x minors; add JSONSchemer for
|
|
57
|
+
schema/instance validation.
|
|
58
|
+
- The Engine now refuses live Act. The full same-session/page/target protocol in this
|
|
59
|
+
baseline is not implemented; earlier fake-only PASS claims did not establish it.
|
|
60
|
+
- Final URLs are no longer inferred when navigation results omit them. The pinned SDK
|
|
61
|
+
permits null results, so actual server behavior must be qualified.
|
|
62
|
+
- SQLite's ignored SELECT FOR UPDATE needs an actual write lock; actor-lock rows and
|
|
63
|
+
atomic start claims now enforce reservations and duplicate-delivery safety.
|
|
64
|
+
- Cancellation holds quota after dispatch until cleanup is confirmed. Prior terminal
|
|
65
|
+
cancellation and swallowed reaper-write failures were not evidence of safe cleanup.
|
|
66
|
+
- No cost ledger or hard currency cap is implemented. Retained-result limits do not
|
|
67
|
+
cap provider response allocations or browser bandwidth.
|
|
68
|
+
|
|
69
|
+
These corrections harden engineering behavior. The owner separately approved exact
|
|
70
|
+
Specs candidate Q `22d488987517b10dcd96d2713ed3d47e8818b36b` at H2 on 2026-10-18;
|
|
71
|
+
that approval does not authorize live use. The owner later authorized release of gem
|
|
72
|
+
version `0.1.0`. The historical candidate label remains `0.3.0-draft` so this record
|
|
73
|
+
does not rewrite the approved Q. See
|
|
74
|
+
[the audit]({% link RELEASE_AUDIT.md %}) for unresolved protocol/product decisions.
|
|
75
|
+
|
|
76
|
+
## Outstanding blockers (carried from the spec baseline)
|
|
77
|
+
|
|
78
|
+
These are **not** satisfied by this repository yet. BR-02 blocks live support. The owner
|
|
79
|
+
has authorized the offline-only `0.1.0` release despite the unresolved live blocker; the
|
|
80
|
+
release does not claim to resolve BR-02.
|
|
81
|
+
|
|
82
|
+
- **BR-02 / live blocker:** a real browser provider must prove browser-side egress
|
|
83
|
+
isolation across navigation, redirects, iframes, popups, subresources, WebSockets and
|
|
84
|
+
metadata routes before live mode is enabled. The first release keeps Stagehand
|
|
85
|
+
unsupported and makes no live calls. Ruby-side URL/DNS checks cannot prove egress.
|
|
86
|
+
- **BR-03 / distribution identity:** the package identifies itself as an unofficial
|
|
87
|
+
community extension and disclaims endorsement. Recheck name availability at publish
|
|
88
|
+
time. The dependency license inventory is technical evidence, not legal clearance.
|
|
89
|
+
- **BR-04:** independent H1 and owner H2 are complete for the exact Q above. Baseline
|
|
90
|
+
registration R remains pending. H2 approved handoff; the owner's later `0.1.0` release
|
|
91
|
+
instruction authorizes publication separately.
|
|
92
|
+
|
|
93
|
+
## Owner scope decision (2026-10-18)
|
|
94
|
+
|
|
95
|
+
The owner selected read-only gem version `0.1.0`, deferred the full live Act protocol to a
|
|
96
|
+
later version, and declined live provider calls. This narrows the first release to the
|
|
97
|
+
offline `FakeBackend` and does not close BR-02 for later live support. Stagehand always
|
|
98
|
+
reports unverified egress, refuses live operations, and sends no provider call including
|
|
99
|
+
cleanup. Unresolved sessions remain `cleanup_pending`. H1/H2 are approved for exact Q;
|
|
100
|
+
registration R remains pending. The later release instruction is recorded separately
|
|
101
|
+
from that historical Specs approval.
|
|
102
|
+
|
|
103
|
+
## Evidence rule
|
|
104
|
+
|
|
105
|
+
Every functional requirement case records test ID, exact versions, run command, fixture,
|
|
106
|
+
result (`PASS` / `FAIL` / `NOT RUN`) and date in `docs/WORK.md`. Mocked tests never
|
|
107
|
+
prove remote browser egress. `NOT RUN` is recorded as `NOT RUN`, never as `PASS`.
|
data/docs/WORK.md
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: WORK Ledger
|
|
4
|
+
description: Track requirement evidence with exact fixtures, commands, dependency versions, and limits.
|
|
5
|
+
llms: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# WORK ledger
|
|
9
|
+
|
|
10
|
+
The implementation repository owns this ledger. Each functional requirement records the
|
|
11
|
+
test ID, exact dependency versions, run command, fixture, result and date. The rule is
|
|
12
|
+
simple: `NOT RUN` is written as `NOT RUN`, never as `PASS`.
|
|
13
|
+
|
|
14
|
+
## Environment used for local runs
|
|
15
|
+
|
|
16
|
+
| Field | Value |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| Ruby | 3.3.5 (arm64-darwin) |
|
|
19
|
+
| RubyLLM | 2.1.1 |
|
|
20
|
+
| Stagehand | 3.21.0 (development only; never called live) |
|
|
21
|
+
| Rails / Active Job | active_record 8.1.4 + active_job 8.1.4, in-memory SQLite (adapter now exercised) |
|
|
22
|
+
| Command | `bundle exec rspec` and `bundle exec rubocop` |
|
|
23
|
+
|
|
24
|
+
## Progress slices (S0 → S4)
|
|
25
|
+
|
|
26
|
+
| Slice | Deliverable | State |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| S0 | Bootstrap: gemspec, version, Ruby-only fixture, CI, OSS docs, baseline record | DONE |
|
|
29
|
+
| S1 | Read-only `Inspect`/`Extract` core with fake backend, policy, bounded results | DONE |
|
|
30
|
+
| S2 | Stagehand adapter, durable operation store, quotas, TTL/reaper, reconciliation | PARTIAL: Stagehand disabled for first release; live egress/final-URL/TTL/cleanup and unknown-start correlation unqualified |
|
|
31
|
+
| S3 | Opt-in `Act` with one-use approvals, Rails 8 jobs, cancellation, negative tests | PARTIAL: read-only Rails jobs tested; offline Act simulation only; full live protocol deferred |
|
|
32
|
+
| S4 | Full matrix, clean install, security/compat/license docs, human-approved release | PARTIAL (Gem builds and clean-installs; compatibility matrix + public release pending) |
|
|
33
|
+
|
|
34
|
+
## Functional-requirement evidence
|
|
35
|
+
|
|
36
|
+
All rows start as `NOT RUN` and are filled in as tests land. Columns: test file(s), run
|
|
37
|
+
command, result, date. Every `PASS` below is a **fake-backend / offline** result; no row
|
|
38
|
+
proves remote browser egress and no live Stagehand call has been run.
|
|
39
|
+
|
|
40
|
+
| FR | Positive | Denial / fault | Result | Date |
|
|
41
|
+
| --- | --- | --- | --- | --- |
|
|
42
|
+
| FR-01 Tool + configuration | `spec/ruby_llm/browser/inspect_spec.rb`, `spec/ruby_llm/browser/extract_spec.rb`, `spec/ruby_llm/browser/context_spec.rb` | `spec/ruby_llm/browser/inspect_spec.rb`, `spec/ruby_llm/browser/extract_spec.rb`, `spec/integration/require_spec.rb` | PASS (fake, no Rails) | 2026-10-17 |
|
|
43
|
+
| FR-02 session/operation | `spec/ruby_llm/browser/engine_spec.rb`, `spec/ruby_llm/browser/fake_backend_spec.rb` | `spec/ruby_llm/browser/engine_spec.rb`, `spec/ruby_llm/browser/in_memory_operation_store_spec.rb` | PASS (fake lifecycle); live Stagehand NOT RUN | 2026-10-17 |
|
|
44
|
+
| FR-03 read-only inspect | `spec/ruby_llm/browser/engine_spec.rb`, `spec/security/url_guard_spec.rb` | `spec/ruby_llm/browser/engine_spec.rb`, `spec/security/url_guard_spec.rb` | PASS (policy/engine); remote-browser egress NOT RUN | 2026-10-17 |
|
|
45
|
+
| FR-04 structured extract | `spec/ruby_llm/browser/extract_spec.rb`, `spec/ruby_llm/browser/engine_spec.rb` | same | PASS (fake) | 2026-10-17 |
|
|
46
|
+
| FR-05 approved Act | `spec/ruby_llm/browser/act_spec.rb`, `spec/ruby_llm/browser/engine_spec.rb` | same, `spec/security/release_audit_spec.rb` | PASS for offline simulation only; live Act deferred, same-session protocol NOT IMPLEMENTED | 2026-10-18 |
|
|
47
|
+
| FR-06 Rails jobs | `spec/rails/operation_job_spec.rb`, `spec/rails/reaper_spec.rb`, `spec/rails/active_record_operation_store_spec.rb`, `spec/rails/active_record_approval_store_spec.rb` | same (wrong actor, fenced-out worker, cancel-mid-session, cleanup_pending visible) | PASS (fake backend + in-memory SQLite) | 2026-10-17 |
|
|
48
|
+
| FR-07 failure/budget/audit | `spec/ruby_llm/browser/engine_spec.rb` (budget, redaction), `spec/ruby_llm/browser/stagehand_backend_spec.rb` | `spec/integration/stagehand_http_spec.rb` (stubbed HTTP; default live calls refused; cleanup ACK not closure), `spec/ruby_llm/browser/doctor_spec.rb` | Offline contract tests only; live Stagehand calls NOT RUN and unsupported | 2026-10-18 |
|
|
49
|
+
| FR-08 full delivery | Build/install evidence below, `spec/integration/documentation_spec.rb` | Core/Rails require, generator/migration and compatibility suites | Package checks PASS; H1/H2 approved for exact Q; owner later authorized the offline-only `0.1.0` release; release outcome is recorded separately | 2026-10-18 |
|
|
50
|
+
|
|
51
|
+
Run command for every row: `bundle exec rspec` (and `bundle exec rubocop`). Environment is
|
|
52
|
+
the pinned local table above.
|
|
53
|
+
|
|
54
|
+
### FR-08 delivery evidence (2026-10-17)
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
$ gem build ruby_llm-browser.gemspec
|
|
58
|
+
Successfully built RubyGem
|
|
59
|
+
Name: ruby_llm-browser
|
|
60
|
+
Version: 0.1.0
|
|
61
|
+
File: ruby_llm-browser-0.1.0.gem
|
|
62
|
+
|
|
63
|
+
# Clean install into an isolated GEM_HOME, then require from the built gem:
|
|
64
|
+
$ gem install --local ./ruby_llm-browser-0.1.0.gem --install-dir "$PKG" --ignore-dependencies
|
|
65
|
+
$ GEM_HOME="$PKG" GEM_PATH="$PKG:$(gem env gempath)" ruby -e 'require "ruby_llm/browser"'
|
|
66
|
+
framework_loaded=[] # no railties / active_record / active_job on the core path
|
|
67
|
+
core=0.1.0
|
|
68
|
+
$ ... ruby -e 'require "ruby_llm/browser/rails"'
|
|
69
|
+
rails=RubyLLM::Browser::Rails::OperationJob
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The packaged gem contains the plain-Ruby core, the opt-in Rails adapter and the install
|
|
73
|
+
generator. At the time of this initial package check, RubyGems publication was blocked on
|
|
74
|
+
BR-03 (name/license clearance).
|
|
75
|
+
|
|
76
|
+
The original install above used `--ignore-dependencies` and borrowed the development
|
|
77
|
+
GEM_PATH. It proved loading the artifact, **not** clean dependency resolution. The later
|
|
78
|
+
audit's fresh-GEM_HOME installation is the stronger check.
|
|
79
|
+
|
|
80
|
+
## Release-hardening audit (2026-10-18)
|
|
81
|
+
|
|
82
|
+
The previous 270-example green suite did not cover several release-critical negative
|
|
83
|
+
paths. The initial new audit regressions failed on output ceilings, malformed schemas,
|
|
84
|
+
missing result validation, stale starts and early quota release. Those are now fixed.
|
|
85
|
+
See the [release audit]({% link RELEASE_AUDIT.md %}) for findings, corrections and remaining gates.
|
|
86
|
+
|
|
87
|
+
Evidence commands (all provider HTTP is stubbed or disabled):
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
bundle exec rake
|
|
91
|
+
BUNDLE_GEMFILE=gemfiles/ruby_llm_2_0.gemfile bundle exec rspec
|
|
92
|
+
BUNDLE_GEMFILE=gemfiles/rails_8_0.gemfile bundle exec rspec
|
|
93
|
+
bundle exec bundle-audit check --update
|
|
94
|
+
bundle exec ruby examples/plain_ruby.rb
|
|
95
|
+
bundle exec ruby examples/rails_adapter.rb
|
|
96
|
+
bundle exec rake build
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Additional fixtures exercise independent SQLite connections, duplicate start claims,
|
|
100
|
+
atomic grant consumption, actual SIGKILL of a fake-backend worker followed by recovery
|
|
101
|
+
in a fresh process, post-start persistence errors, real-clock timestamp precision,
|
|
102
|
+
Stagehand HTTP retries/serialization, the Rails generator's reversible migration, local
|
|
103
|
+
Markdown links, shipped files and executable offline README examples.
|
|
104
|
+
|
|
105
|
+
| Check | Versions / fixture | Result |
|
|
106
|
+
| --- | --- | --- |
|
|
107
|
+
| Full default suite | Ruby 3.3.5, RubyLLM 2.1.1, AR/AJ 8.1.4, Stagehand 3.21.0, SQLite 2.10.0 | PASS: 302 examples, 0 failures |
|
|
108
|
+
| Minimum RubyLLM | Same, RubyLLM 2.0.0 | PASS: 302 examples, 0 failures |
|
|
109
|
+
| Rails 8.0 | Ruby 3.3.5, RubyLLM 2.0.0, AR/AJ 8.0.5.1 | PASS: 302 examples, 0 failures |
|
|
110
|
+
| RuboCop | `bundle exec rubocop . bin/verify-package` | PASS: 89 files, 0 offenses |
|
|
111
|
+
| Runtime dependency advisories | ruby-advisory-db `fa2295251efb3b0d1a300e5ce8ad700ff1f1b485` | No known vulnerabilities found |
|
|
112
|
+
| Live provider egress / TTL / billing / final URL | No live session authorized or run | NOT RUN |
|
|
113
|
+
| PostgreSQL concurrency | No PostgreSQL fixture run | NOT RUN |
|
|
114
|
+
| Expanded remote CI | Linux Ruby 3.2/3.3/3.4, RubyLLM 2.0.0/2.1.1, Rails 8.1 plus Rails 8.0 row | PASS for `0ec34d4`: seven test jobs plus build/install/advisory job |
|
|
115
|
+
| Public release at initial hardening audit | H1/H2 for exact Q, BR-03 naming/license, exact artifact | HOLD at that time; H1/H2 passed, distribution clearance and artifact approval remained open |
|
|
116
|
+
|
|
117
|
+
### Stronger package-install evidence
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
bundle exec rake build
|
|
121
|
+
bundle exec bundle-audit check --update
|
|
122
|
+
bundle exec ruby bin/verify-package --rails --audit
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The verifier installs the actual package and resolves dependencies in a new GEM_HOME
|
|
126
|
+
with no borrowed GEM_PATH and no `--ignore-dependencies`. It runs outside the checkout,
|
|
127
|
+
checks the activated entrypoint, loads shipped guides/examples, proves core loading has
|
|
128
|
+
no eager framework/client, then installs optional Rails dependencies and runs the
|
|
129
|
+
installed generator's migration up/down. Output markers:
|
|
130
|
+
|
|
131
|
+
```text
|
|
132
|
+
CORE_PACKAGE_PASS
|
|
133
|
+
CLEAN_RUNTIME_ADVISORIES_PASS
|
|
134
|
+
RAILS_PACKAGE_PASS
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The initial fresh install exposed vulnerable default CGI/Resolv/URI/zlib versions that
|
|
138
|
+
the project's lockfile scan omitted. After adding patched runtime floors, both the
|
|
139
|
+
lockfile scan and a check of the actually activated clean core runtime report no known
|
|
140
|
+
advisories. Local resolved security libraries: CGI 0.5.2, Resolv 0.8.1, URI 1.1.2 and
|
|
141
|
+
zlib 3.2.4. Native Ruby/system-library security is a separate host responsibility.
|
|
142
|
+
|
|
143
|
+
Full installer/smoke logs and `activated-versions.json` remain in the temporary evidence
|
|
144
|
+
directory printed by the verifier. The verifier prints the artifact SHA-256; a local
|
|
145
|
+
`pkg/SHA256SUMS` accompanies the final artifact. Build/install is not publication.
|
|
146
|
+
|
|
147
|
+
### Submission evidence (2026-10-18)
|
|
148
|
+
|
|
149
|
+
The hardening is committed and pushed as `0ec34d4b48e0e3ab88bb893c4c731777d2aa24af`.
|
|
150
|
+
[CI run 39086570934](https://github.com/yorzi/ruby_llm-browser/actions/runs/39086570934)
|
|
151
|
+
completed successfully: all seven test jobs report `302 examples, 0 failures`, and
|
|
152
|
+
the package job reports no known dependency advisories plus all three clean-install
|
|
153
|
+
success markers. No RubyGems release or paid provider call was performed. Publication
|
|
154
|
+
remains NO-GO for the other recorded gates.
|
|
155
|
+
|
|
156
|
+
### No-provider-dispatch cleanup follow-up (2026-10-18)
|
|
157
|
+
|
|
158
|
+
The owner selected an offline read-only first release, deferred the full live Act
|
|
159
|
+
protocol, and declined live provider calls. The Stagehand adapter refuses every live
|
|
160
|
+
operation. Its end_session method returns false without invoking the SDK; stubbed HTTP
|
|
161
|
+
tests assert that neither normal cleanup nor partial-start cleanup sends an end request.
|
|
162
|
+
This follow-up is local evidence; it is not covered by the CI run above.
|
|
163
|
+
|
|
164
|
+
| Check | Result |
|
|
165
|
+
| --- | --- |
|
|
166
|
+
| `RUBOCOP_CACHE_ROOT=/private/tmp/ruby_llm_browser_rubocop_cache bundle exec rake` (Ruby 3.3.5, RubyLLM 2.1.1, AR/AJ 8.1.4, Stagehand 3.21.0, SQLite 2.10.0) | PASS: 305 examples, 0 failures; RuboCop inspected 94 files, 0 offenses |
|
|
167
|
+
| `BUNDLE_GEMFILE=gemfiles/ruby_llm_2_0.gemfile bundle exec rspec` | PASS: 305 examples, 0 failures; RubyLLM 2.0.0 |
|
|
168
|
+
| `BUNDLE_GEMFILE=gemfiles/rails_8_0.gemfile bundle exec rspec` | PASS: 305 examples, 0 failures; RubyLLM 2.0.0 and Rails/Active Job 8.0.5.1 |
|
|
169
|
+
| `./docs/bin/build.sh` | PASS: Jekyll built the working tree |
|
|
170
|
+
| `bundle exec rake build` | PASS: built `ruby_llm-browser-0.1.0.gem` |
|
|
171
|
+
| `bundle exec ruby bin/verify-package --rails --audit` | PASS: `CORE_PACKAGE_PASS`, `CLEAN_RUNTIME_ADVISORIES_PASS`, `RAILS_PACKAGE_PASS`; final artifact SHA-256 is in ignored `pkg/SHA256SUMS` |
|
|
172
|
+
| Live provider egress, TTL, billing, and cleanup | NOT RUN; no live calls authorized |
|
|
173
|
+
| Current working-tree remote CI | NOT RUN; the passing CI above is for `0ec34d4` |
|
|
174
|
+
| RubyGems publication | NOT ATTEMPTED; H1/H2 passed for exact Q, but name/account/MFA, owner clearance and exact-artifact approval remain open |
|
|
175
|
+
|
|
176
|
+
The clean package verifier needed network access to resolve gems from RubyGems. It ran
|
|
177
|
+
from an isolated temporary GEM_HOME outside the checkout. Its network use was limited to
|
|
178
|
+
gem installation; all example execution used the fake backend. The sandbox-only first
|
|
179
|
+
attempt could not resolve `rubygems.org` and made no install; the permitted retry
|
|
180
|
+
completed successfully. The verifier's SHA-256 output is captured in the local, ignored
|
|
181
|
+
`pkg/SHA256SUMS` sidecar after the final build so this document does not contain a
|
|
182
|
+
self-referential artifact checksum.
|
|
183
|
+
|
|
184
|
+
### Offline Act single-use race and docs (2026-10-18)
|
|
185
|
+
|
|
186
|
+
The first release supports Act only as an offline FakeBackend simulation. It consumes a
|
|
187
|
+
host-issued grant once; competing calls yield one recorded action and stale denials.
|
|
188
|
+
Stagehand remains unsupported, no provider cleanup request is sent, and the full live Act
|
|
189
|
+
protocol remains a later-version feature. The new feature guide explains grant issuance,
|
|
190
|
+
revocation, binding, concurrency, denial results, and this boundary.
|
|
191
|
+
|
|
192
|
+
| Check | Result |
|
|
193
|
+
| --- | --- |
|
|
194
|
+
| `RUBOCOP_CACHE_ROOT=/private/tmp/ruby_llm_browser_rubocop_cache bundle exec rake` | PASS: 306 examples, 0 failures; RuboCop inspected 94 files, 0 offenses |
|
|
195
|
+
| Offline Act guide example via `bundle exec ruby -Ilib -` | PASS: returned `ok` and the issued approval ID; FakeBackend only, no model or provider call |
|
|
196
|
+
| `python3 /Users/andy/.codex/skills/project-docs/scripts/docs.py check --dir docs` | PASS: 12 guides, 0 errors, 0 warnings |
|
|
197
|
+
| `./docs/bin/build.sh` | PASS: Jekyll built the working tree |
|
|
198
|
+
| `bundle exec rake build` | PASS: built `ruby_llm-browser-0.1.0.gem` |
|
|
199
|
+
| `bundle exec ruby bin/verify-package --rails --audit` | PASS: `CORE_PACKAGE_PASS`, `CLEAN_RUNTIME_ADVISORIES_PASS`, and `RAILS_PACKAGE_PASS`; isolated clean install |
|
|
200
|
+
| Live provider egress, TTL, billing, and terminal cleanup | NOT RUN; no live calls authorized |
|
|
201
|
+
| RubyGems publication | NOT ATTEMPTED at this audit snapshot, before the later owner instruction to release version `0.1.0` |
|
|
202
|
+
|
|
203
|
+
These local checks do not qualify browser-side egress, provider TTL, billing, or remote
|
|
204
|
+
cleanup. They validate a local unpublished candidate, not a release. Rebuild the exact
|
|
205
|
+
artifact after any release metadata changes and only after the H1/H2 gates.
|
|
206
|
+
|
|
207
|
+
### H2 handoff and distribution inventory (2026-10-18)
|
|
208
|
+
|
|
209
|
+
The owner approved the offline read-only v1 scope and KPI proposal against exact Specs
|
|
210
|
+
candidate Q `22d488987517b10dcd96d2713ed3d47e8818b36b`. The approval is recorded in
|
|
211
|
+
OddlyNiche content commit C `678f9faed6dfdd8e55a7c54566f94cfa1ad1bc0a`. H1/H2 passed;
|
|
212
|
+
registration R and this repository's final baseline receipt remain pending. H2 does not
|
|
213
|
+
authorize RubyGems publication.
|
|
214
|
+
|
|
215
|
+
| Check | Result |
|
|
216
|
+
| --- | --- |
|
|
217
|
+
| Resolved runtime dependency license inventory | PASS: 26 dependencies' exact lockfile versions and installed gemspec license metadata match NOTICE; Stagehand's missing metadata is covered by its pinned upstream MIT text |
|
|
218
|
+
| RubyGems exact-name query | HTTP 404 on 2026-10-18; unregistered at check time, not reserved |
|
|
219
|
+
| Runtime dependency license inventory | PASS: 26 exact lockfile versions and installed gemspec licenses match NOTICE; Stagehand source MIT text is pinned |
|
|
220
|
+
| Project docs checker | PASS: 12 guide pages, 0 errors, 0 warnings |
|
|
221
|
+
| Jekyll build | PASS: `./docs/bin/build.sh` built the working tree |
|
|
222
|
+
| Local package review | PASS: version 0.1.0, 83 files, 7 runtime dependencies, MFA metadata present, no blocked paths |
|
|
223
|
+
| RubyGems MFA requirement | Gem metadata requires publisher MFA; enable MFA before the first push |
|
|
224
|
+
| RubyGems publication / live provider call | NOT ATTEMPTED; publication awaits exact-artifact approval and distribution clearance; no provider calls were made |
|
|
225
|
+
|
|
226
|
+
The license inventory is a point-in-time metadata check, not legal clearance. Recheck
|
|
227
|
+
name availability and the final built artifact immediately before any release.
|
|
228
|
+
|
|
229
|
+
### 0.1.0 release decision and automation (2026-10-18)
|
|
230
|
+
|
|
231
|
+
After the initial publication hold above, the owner selected gem version `0.1.0`,
|
|
232
|
+
instructed the matching `v0.1.0` tag and RubyGems release, and requested automation for
|
|
233
|
+
future version tags. This instruction authorizes the offline-only package release; it is
|
|
234
|
+
separate from H2 handoff approval. The approved Specs Q keeps its historical candidate
|
|
235
|
+
label `0.3.0-draft`. Stagehand remains unsupported, live Act remains deferred, and no
|
|
236
|
+
provider calls were authorized or made.
|
|
237
|
+
|
|
238
|
+
The repository release workflow runs tests, the dependency advisory scan and isolated
|
|
239
|
+
package verification before RubyGems trusted publishing. It then creates a GitHub Release
|
|
240
|
+
with the generated gem, checksum and matching changelog section. The Docs workflow builds
|
|
241
|
+
the tag's stable documentation only after that release workflow succeeds. The first tag
|
|
242
|
+
is pushed only after the trusted publisher is registered for this repository and the
|
|
243
|
+
`release.yml` workflow under the `release` GitHub environment.
|
|
244
|
+
|
|
245
|
+
## Commit log
|
|
246
|
+
|
|
247
|
+
Small, meaningful commits land one piece at a time. See `git log` for the authoritative
|
|
248
|
+
history; notable slices:
|
|
249
|
+
|
|
250
|
+
1. Scaffold: gemspec, version, Ruby-only fixture, CI, OSS docs and the baseline record.
|
|
251
|
+
2. Core: typed errors, redaction, budgets, results and configuration.
|
|
252
|
+
3. Policy: capabilities, URL guard and source/schema/action policy.
|
|
253
|
+
4. Lifecycle: operation, approval and in-memory stores.
|
|
254
|
+
5. Runtime: backend contract, FakeBackend, Context, Engine and the Inspect/Extract/Act
|
|
255
|
+
tools, with FR-01/03/04/05 evidence (fake backend).
|
|
256
|
+
6. Backend: the Stagehand adapter and preflight Doctor (FR-02/03/07 offline evidence).
|
|
257
|
+
7. Engine seam: a caller-reserved operation for the Rails job and cleanup bookkeeping
|
|
258
|
+
that tolerates a fenced or cancelled writer.
|
|
259
|
+
8. Rails adapter: durable ActiveRecord operation/approval stores, schema and migration.
|
|
260
|
+
9. Rails jobs: scoped Active Job, cleanup reaper and the install generator (FR-06).
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Qualifying a live backend
|
|
4
|
+
nav_order: 2
|
|
5
|
+
description: Review the host and provider guarantees required before a live browser session.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# {{ page.title }}
|
|
9
|
+
|
|
10
|
+
{{ page.description }}
|
|
11
|
+
{: .fs-6 .fw-300 }
|
|
12
|
+
|
|
13
|
+
After reading this guide, you will know:
|
|
14
|
+
|
|
15
|
+
* Why `StagehandBackend` is unsupported in the first release.
|
|
16
|
+
* Which egress and cleanup controls need qualification before live use.
|
|
17
|
+
* Why the full live Act protocol is deferred to a later version.
|
|
18
|
+
|
|
19
|
+
## Run a Local Diagnostic
|
|
20
|
+
|
|
21
|
+
`Doctor` checks local configuration without a network request or browser session. This
|
|
22
|
+
fake-backend example reports its exact boundary:
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
require "ruby_llm/browser"
|
|
26
|
+
|
|
27
|
+
backend = RubyLLM::Browser::FakeBackend.new
|
|
28
|
+
puts RubyLLM::Browser::Doctor.new(backend: backend).report[:summary]
|
|
29
|
+
# => "configuration checks passed; live provider guarantees are not verified"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The diagnostic is local and makes no provider request. In this release it reports the
|
|
33
|
+
built-in Stagehand backend as unsupported: `egress_isolation` remains `:unverified`, and
|
|
34
|
+
the Engine refuses to start a session. The host cannot override this status with a
|
|
35
|
+
constructor option. A custom backend must enforce its own browser-side network boundary.
|
|
36
|
+
|
|
37
|
+
Browserbase's documented [Allowed Domains feature](https://docs.browserbase.com/platform/browser/security/allowed-domains)
|
|
38
|
+
applies to top-frame navigations. It does not block iframe or subresource requests such
|
|
39
|
+
as scripts, images, and XHR. That setting alone cannot qualify provider egress. Any future
|
|
40
|
+
deployment must separately verify DNS at connection time, redirects, frames, popups,
|
|
41
|
+
WebSockets, scripts, and all other request paths.
|
|
42
|
+
|
|
43
|
+
## Verify Provider Behavior Separately
|
|
44
|
+
|
|
45
|
+
Before considering live use, independently establish provider-side egress restrictions,
|
|
46
|
+
final URL reporting, session TTL, unknown-start recovery, billing controls, and confirmed
|
|
47
|
+
cleanup. The gem does not provide a browser firewall or a hard cost cap. The Doctor does
|
|
48
|
+
not call the provider and cannot establish these properties.
|
|
49
|
+
|
|
50
|
+
Cleanup needs a status check. Stagehand 3.21's `SessionEndResponse.success` reports that
|
|
51
|
+
the end request succeeded; it does not report the session's final status. Browserbase's
|
|
52
|
+
[`REQUEST_RELEASE` endpoint](https://docs.browserbase.com/reference/api/update-a-session)
|
|
53
|
+
requests completion and may return a session still marked `PENDING`. The
|
|
54
|
+
[`Get a Session` endpoint](https://docs.browserbase.com/reference/api/get-a-session)
|
|
55
|
+
exposes status and `endedAt`, but the Stagehand Ruby SDK does not expose that lookup.
|
|
56
|
+
The adapter cannot start a live session in this release. Its `end_session` method returns
|
|
57
|
+
`false` without calling the SDK. An operation whose cleanup is not confirmed stays
|
|
58
|
+
`cleanup_pending`; the Gem does not claim terminal cleanup.
|
|
59
|
+
|
|
60
|
+
## Current Project Status
|
|
61
|
+
|
|
62
|
+
The repository's [release audit]({% link RELEASE_AUDIT.md %}) records no live provider
|
|
63
|
+
qualification and marks the built-in Stagehand backend unsupported. The first release
|
|
64
|
+
uses read-only tools; the full live Act protocol is deferred to a later version. The
|
|
65
|
+
Engine refuses non-fake Act calls until same-session host approval and target binding are
|
|
66
|
+
implemented.
|
|
67
|
+
|
|
68
|
+
Read-only tools do not dispatch browser actions. A page can still run scripts and initiate
|
|
69
|
+
requests, and returned page text remains untrusted data. Review the [security model]({% link SECURITY_MODEL.md %}) before designing a host deployment.
|
|
70
|
+
|
|
71
|
+
## Next Steps
|
|
72
|
+
|
|
73
|
+
* [Controlling source access]({% link _core_features/source-policy.md %}) - set host URL policy.
|
|
74
|
+
* [Running work in Rails]({% link _advanced/rails-integration.md %}) - protect durable jobs and recovery.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Running work in Rails
|
|
4
|
+
nav_order: 1
|
|
5
|
+
description: Run durable inspect and extract operations with the Rails 8 adapter.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# {{ page.title }}
|
|
9
|
+
|
|
10
|
+
{{ page.description }}
|
|
11
|
+
{: .fs-6 .fw-300 }
|
|
12
|
+
|
|
13
|
+
After reading this guide, you will know:
|
|
14
|
+
|
|
15
|
+
* Which framework versions and components the adapter expects.
|
|
16
|
+
* How to install its tables.
|
|
17
|
+
* What the host must own in background jobs and cleanup.
|
|
18
|
+
|
|
19
|
+
## Install the Adapter
|
|
20
|
+
|
|
21
|
+
The adapter is optional. Add Rails 8 Active Record and Active Job to the host application,
|
|
22
|
+
then require the Rails entry point and install its migration:
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
require "ruby_llm/browser/rails"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
bin/rails generate ruby_llm:browser:install
|
|
30
|
+
bin/rails db:migrate
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The generator creates durable operation and approval tables plus per-actor reservation
|
|
34
|
+
locks. The jobs accept `inspect` and `extract`; Act is not available in background jobs.
|
|
35
|
+
|
|
36
|
+
## Keep Authorization in the Host
|
|
37
|
+
|
|
38
|
+
The context factory runs in the worker and must reload trusted records, recheck actor and
|
|
39
|
+
run authorization, and use the same operation store and budget limits as the reservation.
|
|
40
|
+
Never put provider credentials or authorization decisions in model arguments or job
|
|
41
|
+
payloads. Protect queue storage because URLs, instructions, and schemas are persisted.
|
|
42
|
+
|
|
43
|
+
## Schedule Recovery
|
|
44
|
+
|
|
45
|
+
Run `RubyLLM::Browser::Rails::Reaper` on a separate schedule. Worker cleanup alone cannot
|
|
46
|
+
recover sessions left by a killed process. Do not free quota for an unknown or pending
|
|
47
|
+
session based only on elapsed time. The job does not durably store result bodies, so the
|
|
48
|
+
host must implement authorized result storage and delivery if it needs them.
|
|
49
|
+
|
|
50
|
+
SQLite concurrency is exercised locally. PostgreSQL still needs separate qualification,
|
|
51
|
+
and MySQL is not supported by the adapter's locking contract. See the [full Rails guide]({% link RAILS.md %}) for a context factory, enqueueing, status access, migration recovery, and reaper details.
|
|
52
|
+
|
|
53
|
+
## Next Steps
|
|
54
|
+
|
|
55
|
+
* [Bounding operation work]({% link _core_features/operation-lifecycle.md %}) - understand budgets and state transitions.
|
|
56
|
+
* [Qualifying a live backend]({% link _advanced/live-backend-qualification.md %}) - review provider requirements.
|