browserrig 0.1.0__tar.gz

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.
Files changed (274) hide show
  1. browserrig-0.1.0/.env.example +10 -0
  2. browserrig-0.1.0/.gitattributes +2 -0
  3. browserrig-0.1.0/.github/workflows/checks.yml +89 -0
  4. browserrig-0.1.0/.github/workflows/release.yml +83 -0
  5. browserrig-0.1.0/.gitignore +17 -0
  6. browserrig-0.1.0/.pre-commit-config.yml +47 -0
  7. browserrig-0.1.0/.prettierignore +7 -0
  8. browserrig-0.1.0/.prettierrc.json +6 -0
  9. browserrig-0.1.0/.smelt/debt.json +56 -0
  10. browserrig-0.1.0/.smelt.schema.json +3596 -0
  11. browserrig-0.1.0/CHANGELOG.md +27 -0
  12. browserrig-0.1.0/LICENSE +21 -0
  13. browserrig-0.1.0/PKG-INFO +174 -0
  14. browserrig-0.1.0/README.md +124 -0
  15. browserrig-0.1.0/browserrig/__init__.py +158 -0
  16. browserrig-0.1.0/browserrig/activity/__init__.py +5 -0
  17. browserrig-0.1.0/browserrig/activity/models.py +93 -0
  18. browserrig-0.1.0/browserrig/activity/plugin.py +247 -0
  19. browserrig-0.1.0/browserrig/activity/state.py +16 -0
  20. browserrig-0.1.0/browserrig/agent.py +55 -0
  21. browserrig-0.1.0/browserrig/browser/__init__.py +33 -0
  22. browserrig-0.1.0/browserrig/browser/base.py +70 -0
  23. browserrig-0.1.0/browserrig/browser/chrome.py +242 -0
  24. browserrig-0.1.0/browserrig/browser/config.py +119 -0
  25. browserrig-0.1.0/browserrig/browser/downloads.py +128 -0
  26. browserrig-0.1.0/browserrig/browser/favicon.py +119 -0
  27. browserrig-0.1.0/browserrig/browser/frame.py +227 -0
  28. browserrig-0.1.0/browserrig/browser/frames.py +116 -0
  29. browserrig-0.1.0/browserrig/browser/images.py +23 -0
  30. browserrig-0.1.0/browserrig/browser/input.py +147 -0
  31. browserrig-0.1.0/browserrig/browser/models.py +8 -0
  32. browserrig-0.1.0/browserrig/browser/plugin.py +44 -0
  33. browserrig-0.1.0/browserrig/browser/process.py +144 -0
  34. browserrig-0.1.0/browserrig/browser/setup.py +12 -0
  35. browserrig-0.1.0/browserrig/browser/tab.py +311 -0
  36. browserrig-0.1.0/browserrig/browser/tabs.py +366 -0
  37. browserrig-0.1.0/browserrig/browser/worlds.py +64 -0
  38. browserrig-0.1.0/browserrig/choreography/__init__.py +31 -0
  39. browserrig-0.1.0/browserrig/choreography/events.py +133 -0
  40. browserrig-0.1.0/browserrig/choreography/plugin.py +75 -0
  41. browserrig-0.1.0/browserrig/choreography/scenes.py +167 -0
  42. browserrig-0.1.0/browserrig/choreography/stage.py +53 -0
  43. browserrig-0.1.0/browserrig/choreography/tabstrip.py +112 -0
  44. browserrig-0.1.0/browserrig/completion.py +184 -0
  45. browserrig-0.1.0/browserrig/composition.py +108 -0
  46. browserrig-0.1.0/browserrig/core/__init__.py +61 -0
  47. browserrig-0.1.0/browserrig/core/errors.py +18 -0
  48. browserrig-0.1.0/browserrig/core/geometry.py +149 -0
  49. browserrig-0.1.0/browserrig/core/ids.py +10 -0
  50. browserrig-0.1.0/browserrig/core/kinds.py +180 -0
  51. browserrig-0.1.0/browserrig/core/options.py +7 -0
  52. browserrig-0.1.0/browserrig/core/tools.py +32 -0
  53. browserrig-0.1.0/browserrig/events.py +665 -0
  54. browserrig-0.1.0/browserrig/files/__init__.py +25 -0
  55. browserrig-0.1.0/browserrig/files/config.py +13 -0
  56. browserrig-0.1.0/browserrig/files/containers.py +200 -0
  57. browserrig-0.1.0/browserrig/files/content.py +65 -0
  58. browserrig-0.1.0/browserrig/files/data.py +80 -0
  59. browserrig-0.1.0/browserrig/files/documents.py +248 -0
  60. browserrig-0.1.0/browserrig/files/formats.py +84 -0
  61. browserrig-0.1.0/browserrig/files/imaging.py +138 -0
  62. browserrig-0.1.0/browserrig/files/kinds.py +78 -0
  63. browserrig-0.1.0/browserrig/files/models.py +71 -0
  64. browserrig-0.1.0/browserrig/files/reading.py +382 -0
  65. browserrig-0.1.0/browserrig/files/spreadsheets.py +417 -0
  66. browserrig-0.1.0/browserrig/files/system.py +204 -0
  67. browserrig-0.1.0/browserrig/files/text.py +64 -0
  68. browserrig-0.1.0/browserrig/files/xlsx.py +53 -0
  69. browserrig-0.1.0/browserrig/handoff/__init__.py +4 -0
  70. browserrig-0.1.0/browserrig/handoff/changes.py +48 -0
  71. browserrig-0.1.0/browserrig/handoff/models.py +31 -0
  72. browserrig-0.1.0/browserrig/handoff/plugin.py +308 -0
  73. browserrig-0.1.0/browserrig/handoff/state.py +21 -0
  74. browserrig-0.1.0/browserrig/input/__init__.py +35 -0
  75. browserrig-0.1.0/browserrig/input/controller.py +69 -0
  76. browserrig-0.1.0/browserrig/input/keyboard.py +267 -0
  77. browserrig-0.1.0/browserrig/input/motor.py +118 -0
  78. browserrig-0.1.0/browserrig/input/mouse.py +346 -0
  79. browserrig-0.1.0/browserrig/input/pointer.py +84 -0
  80. browserrig-0.1.0/browserrig/input/presenter.py +49 -0
  81. browserrig-0.1.0/browserrig/input/target.py +67 -0
  82. browserrig-0.1.0/browserrig/input/wheel.py +40 -0
  83. browserrig-0.1.0/browserrig/kinds.py +33 -0
  84. browserrig-0.1.0/browserrig/nudges/__init__.py +3 -0
  85. browserrig-0.1.0/browserrig/nudges/plugin.py +295 -0
  86. browserrig-0.1.0/browserrig/nudges/state.py +23 -0
  87. browserrig-0.1.0/browserrig/observation/__init__.py +53 -0
  88. browserrig-0.1.0/browserrig/observation/capture.py +374 -0
  89. browserrig-0.1.0/browserrig/observation/changes.py +63 -0
  90. browserrig-0.1.0/browserrig/observation/config.py +12 -0
  91. browserrig-0.1.0/browserrig/observation/content.py +176 -0
  92. browserrig-0.1.0/browserrig/observation/delta.py +69 -0
  93. browserrig-0.1.0/browserrig/observation/dom.py +97 -0
  94. browserrig-0.1.0/browserrig/observation/extraction/__init__.py +335 -0
  95. browserrig-0.1.0/browserrig/observation/extraction/accessibility.py +62 -0
  96. browserrig-0.1.0/browserrig/observation/extraction/document.py +471 -0
  97. browserrig-0.1.0/browserrig/observation/extraction/elements.py +676 -0
  98. browserrig-0.1.0/browserrig/observation/extraction/semantics.py +351 -0
  99. browserrig-0.1.0/browserrig/observation/extraction/styles.py +30 -0
  100. browserrig-0.1.0/browserrig/observation/extraction/visibility.py +108 -0
  101. browserrig-0.1.0/browserrig/observation/find.py +152 -0
  102. browserrig-0.1.0/browserrig/observation/handle.py +170 -0
  103. browserrig-0.1.0/browserrig/observation/images.py +243 -0
  104. browserrig-0.1.0/browserrig/observation/marks.py +157 -0
  105. browserrig-0.1.0/browserrig/observation/models.py +230 -0
  106. browserrig-0.1.0/browserrig/observation/plugin.py +413 -0
  107. browserrig-0.1.0/browserrig/observation/redirects.py +40 -0
  108. browserrig-0.1.0/browserrig/observation/references.py +47 -0
  109. browserrig-0.1.0/browserrig/observation/render.py +291 -0
  110. browserrig-0.1.0/browserrig/observation/renderer.py +76 -0
  111. browserrig-0.1.0/browserrig/observation/state.py +37 -0
  112. browserrig-0.1.0/browserrig/pacing/__init__.py +5 -0
  113. browserrig-0.1.0/browserrig/pacing/plugin.py +22 -0
  114. browserrig-0.1.0/browserrig/py.typed +0 -0
  115. browserrig-0.1.0/browserrig/readiness/__init__.py +25 -0
  116. browserrig-0.1.0/browserrig/readiness/config.py +12 -0
  117. browserrig-0.1.0/browserrig/readiness/dom.py +83 -0
  118. browserrig-0.1.0/browserrig/readiness/downloads.py +30 -0
  119. browserrig-0.1.0/browserrig/readiness/hooks.py +27 -0
  120. browserrig-0.1.0/browserrig/readiness/models.py +13 -0
  121. browserrig-0.1.0/browserrig/readiness/plugin.py +170 -0
  122. browserrig-0.1.0/browserrig/readiness/policies.py +43 -0
  123. browserrig-0.1.0/browserrig/readiness/state.py +20 -0
  124. browserrig-0.1.0/browserrig/readiness/strategy.py +30 -0
  125. browserrig-0.1.0/browserrig/readiness/wait.py +238 -0
  126. browserrig-0.1.0/browserrig/scripts/README.md +39 -0
  127. browserrig-0.1.0/browserrig/scripts/__init__.py +186 -0
  128. browserrig-0.1.0/browserrig/scripts/content.js +526 -0
  129. browserrig-0.1.0/browserrig/scripts/cursor.js +57 -0
  130. browserrig-0.1.0/browserrig/scripts/element.js +82 -0
  131. browserrig-0.1.0/browserrig/scripts/find.js +377 -0
  132. browserrig-0.1.0/browserrig/scripts/focused.js +15 -0
  133. browserrig-0.1.0/browserrig/scripts/lib/composed.js +21 -0
  134. browserrig-0.1.0/browserrig/scripts/lib/elements.js +9 -0
  135. browserrig-0.1.0/browserrig/scripts/lib/geometry.js +13 -0
  136. browserrig-0.1.0/browserrig/scripts/lib/hit.js +84 -0
  137. browserrig-0.1.0/browserrig/scripts/lib/markdown.js +32 -0
  138. browserrig-0.1.0/browserrig/scripts/lib/scroll.js +226 -0
  139. browserrig-0.1.0/browserrig/scripts/lib/secret.js +74 -0
  140. browserrig-0.1.0/browserrig/scripts/lib/visibility.js +42 -0
  141. browserrig-0.1.0/browserrig/scripts/models.py +153 -0
  142. browserrig-0.1.0/browserrig/scripts/owner_hits.js +4 -0
  143. browserrig-0.1.0/browserrig/scripts/owner_scroll.js +7 -0
  144. browserrig-0.1.0/browserrig/scripts/owner_size.js +11 -0
  145. browserrig-0.1.0/browserrig/scripts/page_facts.js +9 -0
  146. browserrig-0.1.0/browserrig/scripts/reset.js +4 -0
  147. browserrig-0.1.0/browserrig/scripts/scroll.js +5 -0
  148. browserrig-0.1.0/browserrig/scripts/secret_field.js +7 -0
  149. browserrig-0.1.0/browserrig/scripts/secret_focus.js +31 -0
  150. browserrig-0.1.0/browserrig/scripts/seed.js +13 -0
  151. browserrig-0.1.0/browserrig/scripts/stability.js +140 -0
  152. browserrig-0.1.0/browserrig/scripts/tab_strip.js +27 -0
  153. browserrig-0.1.0/browserrig/scripts/viewport.js +3 -0
  154. browserrig-0.1.0/browserrig/secrets/__init__.py +5 -0
  155. browserrig-0.1.0/browserrig/secrets/models.py +90 -0
  156. browserrig-0.1.0/browserrig/secrets/origin.py +95 -0
  157. browserrig-0.1.0/browserrig/secrets/plugin.py +397 -0
  158. browserrig-0.1.0/browserrig/secrets/redaction.py +107 -0
  159. browserrig-0.1.0/browserrig/secrets/state.py +6 -0
  160. browserrig-0.1.0/browserrig/secrets/totp.py +62 -0
  161. browserrig-0.1.0/browserrig/terminal.py +120 -0
  162. browserrig-0.1.0/browserrig/tools/__init__.py +51 -0
  163. browserrig-0.1.0/browserrig/tools/chains.py +55 -0
  164. browserrig-0.1.0/browserrig/tools/dialogs.py +23 -0
  165. browserrig-0.1.0/browserrig/tools/effects.py +8 -0
  166. browserrig-0.1.0/browserrig/tools/execution.py +333 -0
  167. browserrig-0.1.0/browserrig/tools/files.py +411 -0
  168. browserrig-0.1.0/browserrig/tools/find.py +125 -0
  169. browserrig-0.1.0/browserrig/tools/forms.py +76 -0
  170. browserrig-0.1.0/browserrig/tools/intents.py +82 -0
  171. browserrig-0.1.0/browserrig/tools/javascript.py +37 -0
  172. browserrig-0.1.0/browserrig/tools/keyboard.py +126 -0
  173. browserrig-0.1.0/browserrig/tools/mouse.py +224 -0
  174. browserrig-0.1.0/browserrig/tools/navigation.py +189 -0
  175. browserrig-0.1.0/browserrig/tools/scrolling.py +39 -0
  176. browserrig-0.1.0/browserrig/tools/tabs.py +81 -0
  177. browserrig-0.1.0/browserrig/tools/targeting.py +59 -0
  178. browserrig-0.1.0/compose.yml +20 -0
  179. browserrig-0.1.0/docs/agent-guide.md +497 -0
  180. browserrig-0.1.0/docs/browser-composition.md +356 -0
  181. browserrig-0.1.0/docs/browser-interaction.md +418 -0
  182. browserrig-0.1.0/docs/development.md +141 -0
  183. browserrig-0.1.0/docs/files-and-events.md +221 -0
  184. browserrig-0.1.0/docs/harnessed-telemetry-feedback.md +62 -0
  185. browserrig-0.1.0/docs/human-handoff.md +91 -0
  186. browserrig-0.1.0/docs/telemetry.md +231 -0
  187. browserrig-0.1.0/eslint.config.mjs +44 -0
  188. browserrig-0.1.0/examples/__init__.py +1 -0
  189. browserrig-0.1.0/examples/connect_browser.py +33 -0
  190. browserrig-0.1.0/examples/controls.py +42 -0
  191. browserrig-0.1.0/examples/direct_browser.py +25 -0
  192. browserrig-0.1.0/examples/openai_agent.py +92 -0
  193. browserrig-0.1.0/examples/session_store.py +49 -0
  194. browserrig-0.1.0/examples/telemetry.py +91 -0
  195. browserrig-0.1.0/examples/tracing_smoke.py +85 -0
  196. browserrig-0.1.0/package.json +19 -0
  197. browserrig-0.1.0/pnpm-lock.yaml +812 -0
  198. browserrig-0.1.0/pyproject.toml +131 -0
  199. browserrig-0.1.0/smelt.yml +113 -0
  200. browserrig-0.1.0/tests/__init__.py +0 -0
  201. browserrig-0.1.0/tests/check_distribution.py +69 -0
  202. browserrig-0.1.0/tests/check_file_corpus.py +141 -0
  203. browserrig-0.1.0/tests/check_release.py +47 -0
  204. browserrig-0.1.0/tests/conftest.py +172 -0
  205. browserrig-0.1.0/tests/fakes.py +169 -0
  206. browserrig-0.1.0/tests/file_corpus.json +330 -0
  207. browserrig-0.1.0/tests/javascript.py +23 -0
  208. browserrig-0.1.0/tests/observations.py +83 -0
  209. browserrig-0.1.0/tests/test_actions.py +206 -0
  210. browserrig-0.1.0/tests/test_activity.py +389 -0
  211. browserrig-0.1.0/tests/test_agent_facade_integration.py +130 -0
  212. browserrig-0.1.0/tests/test_agent_integration.py +276 -0
  213. browserrig-0.1.0/tests/test_architecture.py +15 -0
  214. browserrig-0.1.0/tests/test_archive_input_limit.py +58 -0
  215. browserrig-0.1.0/tests/test_attached_context_integration.py +38 -0
  216. browserrig-0.1.0/tests/test_browser_composition.py +910 -0
  217. browserrig-0.1.0/tests/test_browser_integration.py +113 -0
  218. browserrig-0.1.0/tests/test_capture.py +82 -0
  219. browserrig-0.1.0/tests/test_chains.py +284 -0
  220. browserrig-0.1.0/tests/test_chains_integration.py +312 -0
  221. browserrig-0.1.0/tests/test_choreography.py +490 -0
  222. browserrig-0.1.0/tests/test_chrome.py +310 -0
  223. browserrig-0.1.0/tests/test_completion.py +367 -0
  224. browserrig-0.1.0/tests/test_composition.py +190 -0
  225. browserrig-0.1.0/tests/test_content_integration.py +346 -0
  226. browserrig-0.1.0/tests/test_controls_integration.py +117 -0
  227. browserrig-0.1.0/tests/test_delta.py +53 -0
  228. browserrig-0.1.0/tests/test_dependencies.py +440 -0
  229. browserrig-0.1.0/tests/test_download_integration.py +366 -0
  230. browserrig-0.1.0/tests/test_elements_integration.py +130 -0
  231. browserrig-0.1.0/tests/test_events.py +69 -0
  232. browserrig-0.1.0/tests/test_extraction_budget.py +47 -0
  233. browserrig-0.1.0/tests/test_file_readers.py +484 -0
  234. browserrig-0.1.0/tests/test_files.py +460 -0
  235. browserrig-0.1.0/tests/test_find_integration.py +190 -0
  236. browserrig-0.1.0/tests/test_frames_integration.py +268 -0
  237. browserrig-0.1.0/tests/test_gestures_integration.py +200 -0
  238. browserrig-0.1.0/tests/test_handoff.py +466 -0
  239. browserrig-0.1.0/tests/test_input.py +770 -0
  240. browserrig-0.1.0/tests/test_input_integration.py +333 -0
  241. browserrig-0.1.0/tests/test_javascript.py +101 -0
  242. browserrig-0.1.0/tests/test_javascript_integration.py +108 -0
  243. browserrig-0.1.0/tests/test_kit.py +251 -0
  244. browserrig-0.1.0/tests/test_marks.py +70 -0
  245. browserrig-0.1.0/tests/test_models.py +255 -0
  246. browserrig-0.1.0/tests/test_navigation.py +61 -0
  247. browserrig-0.1.0/tests/test_navigation_integration.py +67 -0
  248. browserrig-0.1.0/tests/test_nudges.py +398 -0
  249. browserrig-0.1.0/tests/test_observation_integration.py +432 -0
  250. browserrig-0.1.0/tests/test_optional_defaults.py +46 -0
  251. browserrig-0.1.0/tests/test_process.py +102 -0
  252. browserrig-0.1.0/tests/test_readiness.py +476 -0
  253. browserrig-0.1.0/tests/test_readiness_integration.py +302 -0
  254. browserrig-0.1.0/tests/test_redirects.py +70 -0
  255. browserrig-0.1.0/tests/test_references.py +511 -0
  256. browserrig-0.1.0/tests/test_references_integration.py +145 -0
  257. browserrig-0.1.0/tests/test_release.py +49 -0
  258. browserrig-0.1.0/tests/test_scripts.py +191 -0
  259. browserrig-0.1.0/tests/test_scripts_integration.py +105 -0
  260. browserrig-0.1.0/tests/test_secret_javascript_guard.py +31 -0
  261. browserrig-0.1.0/tests/test_secret_javascript_guard_integration.py +31 -0
  262. browserrig-0.1.0/tests/test_secret_screenshots.py +68 -0
  263. browserrig-0.1.0/tests/test_secret_screenshots_integration.py +35 -0
  264. browserrig-0.1.0/tests/test_secret_unicode.py +29 -0
  265. browserrig-0.1.0/tests/test_secrets.py +476 -0
  266. browserrig-0.1.0/tests/test_secrets_integration.py +230 -0
  267. browserrig-0.1.0/tests/test_session_store.py +139 -0
  268. browserrig-0.1.0/tests/test_tab_state.py +292 -0
  269. browserrig-0.1.0/tests/test_tab_state_integration.py +132 -0
  270. browserrig-0.1.0/tests/test_telemetry.py +218 -0
  271. browserrig-0.1.0/tests/test_terminal.py +120 -0
  272. browserrig-0.1.0/tests/test_viewport_integration.py +365 -0
  273. browserrig-0.1.0/tests/test_worlds.py +70 -0
  274. browserrig-0.1.0/uv.lock +2777 -0
@@ -0,0 +1,10 @@
1
+ # Credentials belong to the provider selected by your host application.
2
+ OPENAI_API_KEY=
3
+ OPENAI_MODEL=gpt-6.1-terra
4
+ # BROWSERRIG_CHROME=C:/Program Files/Google/Chrome/Application/chrome.exe
5
+
6
+ # Optional tracing: docker compose up -d --wait, then add --trace-content to the example.
7
+ # --trace captures metadata only; --trace-content includes model/tool inputs and outputs.
8
+ # OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://127.0.0.1:6006/v1/traces
9
+ # OTEL_SERVICE_NAME=browserrig
10
+ # PHOENIX_PROJECT_NAME=browserrig
@@ -0,0 +1,2 @@
1
+ *.js text eol=lf
2
+ *.mjs text eol=lf
@@ -0,0 +1,89 @@
1
+ name: checks
2
+
3
+ on:
4
+ push:
5
+ branches: ['**']
6
+ pull_request:
7
+ workflow_call:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ offline:
14
+ runs-on: ${{ matrix.os }}
15
+ strategy:
16
+ matrix:
17
+ os: [ubuntu-latest, windows-latest]
18
+ python: ['3.12', '3.13', '3.14']
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: astral-sh/setup-uv@v6
22
+ with:
23
+ python-version: ${{ matrix.python }}
24
+ - run: uv sync --locked --extra openai --extra mcp --extra otel
25
+ - run: uv run --no-sync prek validate-config .pre-commit-config.yml
26
+ - run: uv run --no-sync ruff check browserrig examples tests
27
+ - run: uv run --no-sync ruff format --check browserrig examples tests
28
+ - run: uv run --no-sync pylint browserrig examples tests
29
+ - run: uv run --no-sync ty check
30
+ - run: uv run --no-sync smelt check --fail-on warning --format github
31
+ - run: uv run --no-sync pytest -m "not integration"
32
+ - name: Check release metadata
33
+ run: uv run --no-sync python tests/check_release.py
34
+ - run: uv build
35
+ - name: Check installed wheel in a clean environment
36
+ run: uv run --no-sync python tests/check_distribution.py
37
+ - run: uv run --no-sync python -m examples.openai_agent --help
38
+
39
+ javascript:
40
+ runs-on: ubuntu-latest
41
+ steps:
42
+ - uses: actions/checkout@v4
43
+ - uses: pnpm/action-setup@v4
44
+ - uses: actions/setup-node@v4
45
+ with:
46
+ node-version: '24'
47
+ cache: pnpm
48
+ - run: pnpm install --frozen-lockfile
49
+ - run: pnpm run lint
50
+ - run: pnpm run format:check
51
+
52
+ chrome:
53
+ runs-on: ubuntu-latest
54
+ steps:
55
+ - uses: actions/checkout@v4
56
+ - uses: astral-sh/setup-uv@v6
57
+ with:
58
+ python-version: '3.14'
59
+ - uses: browser-actions/setup-chrome@v2
60
+ id: chrome
61
+ - name: Allow Chrome sandbox user namespaces
62
+ env:
63
+ BROWSERRIG_CHROME: ${{ steps.chrome.outputs.chrome-path }}
64
+ run: |
65
+ # Ubuntu restricts user namespaces for binaries outside packaged browser paths.
66
+ # Allow only this Chrome for Testing binary to use its sandbox.
67
+ # https://chromium.googlesource.com/chromium/src/+/main/docs/security/apparmor-userns-restrictions.md
68
+ cat <<EOF | sudo tee /etc/apparmor.d/browserrig-chrome > /dev/null
69
+ abi <abi/4.0>,
70
+ include <tunables/global>
71
+
72
+ profile browserrig-chrome "$BROWSERRIG_CHROME" flags=(unconfined) {
73
+ userns,
74
+ }
75
+ EOF
76
+ sudo apparmor_parser -r /etc/apparmor.d/browserrig-chrome
77
+ - name: Check Chrome startup
78
+ env:
79
+ BROWSERRIG_CHROME: ${{ steps.chrome.outputs.chrome-path }}
80
+ run: timeout 20s "$BROWSERRIG_CHROME" --headless=new --dump-dom about:blank
81
+ - run: uv sync --locked
82
+ - run: uv run --no-sync pytest -m integration
83
+ env:
84
+ BROWSERRIG_CHROME: ${{ steps.chrome.outputs.chrome-path }}
85
+
86
+ - name: Direct browser example smoke test
87
+ run: uv run --no-sync python -m examples.direct_browser --url about:blank
88
+ env:
89
+ BROWSERRIG_CHROME: ${{ steps.chrome.outputs.chrome-path }}
@@ -0,0 +1,83 @@
1
+ name: Release package
2
+
3
+ on:
4
+ push:
5
+ tags: ['v*']
6
+ release:
7
+ types: [published]
8
+ # A manual run checks and builds only. Publishing requires a tag or release.
9
+ workflow_dispatch:
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ concurrency:
15
+ group: release-${{ github.event.release.tag_name || github.ref_name }}
16
+ cancel-in-progress: false
17
+
18
+ jobs:
19
+ checks:
20
+ uses: ./.github/workflows/checks.yml
21
+
22
+ build:
23
+ name: Build and verify release artifacts
24
+ needs: checks
25
+ runs-on: ubuntu-latest
26
+ timeout-minutes: 20
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ with:
30
+ fetch-depth: 0
31
+ persist-credentials: false
32
+ - uses: astral-sh/setup-uv@v6
33
+ with:
34
+ version: '0.9.2'
35
+ python-version: '3.14'
36
+ - name: Validate version, tag and main ancestry
37
+ env:
38
+ RELEASE_TAG: ${{ github.event.release.tag_name || (github.ref_type == 'tag' && github.ref_name) || '' }}
39
+ run: |
40
+ args=()
41
+ if [[ -n "$RELEASE_TAG" ]]; then
42
+ git merge-base --is-ancestor HEAD origin/main || {
43
+ echo 'Release tags must point to a commit on main.' >&2
44
+ exit 1
45
+ }
46
+ args+=(--tag "$RELEASE_TAG")
47
+ fi
48
+ uv run --no-project python tests/check_release.py "${args[@]}"
49
+ echo "SOURCE_DATE_EPOCH=$(git show -s --format=%ct HEAD)" >> "$GITHUB_ENV"
50
+ # uv builds the wheel from the sdist, so both upload artifacts are exercised.
51
+ - run: uv build --out-dir dist/release
52
+ - name: Check PyPI metadata and README rendering
53
+ run: uvx twine check --strict dist/release/*
54
+ - name: Check installed release wheel in a clean environment
55
+ run: uv run --no-project python tests/check_distribution.py dist/release
56
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
57
+ with:
58
+ name: python-release-distributions
59
+ path: dist/release/*
60
+ if-no-files-found: error
61
+ retention-days: 30
62
+
63
+ publish:
64
+ name: Publish verified artifacts to PyPI
65
+ if: github.event_name == 'push' || github.event_name == 'release'
66
+ needs: build
67
+ runs-on: ubuntu-latest
68
+ timeout-minutes: 15
69
+ environment:
70
+ name: pypi
71
+ url: https://pypi.org/project/browserrig/
72
+ permissions:
73
+ id-token: write
74
+ steps:
75
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
76
+ with:
77
+ name: python-release-distributions
78
+ path: dist/
79
+ - name: Publish with PyPI Trusted Publishing
80
+ uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # release/v1
81
+ with:
82
+ # Tag pushes and published releases can refer to the same version.
83
+ skip-existing: true
@@ -0,0 +1,17 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ .uv-cache/
7
+ .smelt_cache/
8
+ dist/
9
+ build/
10
+ *.egg-info/
11
+ .env
12
+ .browserrig/
13
+ node_modules/
14
+
15
+ # Exported Phoenix traces (px trace list ./traces)
16
+ traces/
17
+ evals/results/
@@ -0,0 +1,47 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ - id: ruff
5
+ name: Ruff lint
6
+ entry: uv run --locked ruff check browserrig examples tests
7
+ language: system
8
+ files: '^((browserrig|examples|tests)/.*\.py|pyproject\.toml|uv\.lock)$'
9
+ pass_filenames: false
10
+ - id: ruff-format
11
+ name: Ruff format
12
+ entry: uv run --locked ruff format --check browserrig examples tests
13
+ language: system
14
+ files: '^((browserrig|examples|tests)/.*\.py|pyproject\.toml|uv\.lock)$'
15
+ pass_filenames: false
16
+ - id: pylint
17
+ name: Pylint
18
+ entry: uv run --locked pylint browserrig examples tests
19
+ language: system
20
+ files: '^((browserrig|examples|tests)/.*\.py|pyproject\.toml|uv\.lock)$'
21
+ pass_filenames: false
22
+ require_serial: true
23
+ - id: ty
24
+ name: ty
25
+ entry: uv run --locked ty check
26
+ language: system
27
+ files: '^((browserrig|examples|tests)/.*\.py|pyproject\.toml|uv\.lock)$'
28
+ pass_filenames: false
29
+ - id: smelt
30
+ name: Smelt
31
+ entry: uv run --locked smelt check --fail-on warning
32
+ language: system
33
+ always_run: true
34
+ pass_filenames: false
35
+ require_serial: true
36
+ - id: eslint
37
+ name: ESLint
38
+ entry: pnpm run lint
39
+ language: system
40
+ files: '(\.(js|mjs)$|^package\.json$|^pnpm-lock\.yaml$)'
41
+ pass_filenames: false
42
+ - id: prettier
43
+ name: JavaScript format
44
+ entry: pnpm run format:check
45
+ language: system
46
+ files: '(\.(js|mjs)$|^\.prettier(rc\.json|ignore)$|^package\.json$|^pnpm-lock\.yaml$)'
47
+ pass_filenames: false
@@ -0,0 +1,7 @@
1
+ .venv/
2
+ .pytest_cache/
3
+ .ruff_cache/
4
+ .browserrig/
5
+ **/__pycache__/
6
+ build/
7
+ dist/
@@ -0,0 +1,6 @@
1
+ {
2
+ "singleQuote": true,
3
+ "bracketSpacing": false,
4
+ "printWidth": 88,
5
+ "endOfLine": "lf"
6
+ }
@@ -0,0 +1,56 @@
1
+ {
2
+ "version": 2,
3
+ "violations": [
4
+ {
5
+ "code": "SMT420",
6
+ "path": "tests/test_browser_composition.py",
7
+ "message": "test accesses private production name browserrig.Observe._page_key",
8
+ "fingerprints": [
9
+ "a1be727efcd1fb823790a19dde96d4f8",
10
+ "a1be727efcd1fb823790a19dde96d4f8",
11
+ "a1be727efcd1fb823790a19dde96d4f8",
12
+ "a1be727efcd1fb823790a19dde96d4f8"
13
+ ]
14
+ },
15
+ {
16
+ "code": "SMT420",
17
+ "path": "tests/test_browser_composition.py",
18
+ "message": "test accesses private production name browserrig.tools.mouse._image_point",
19
+ "fingerprints": [
20
+ "57c4c77eee7729fb96b74d1b3216eecb"
21
+ ]
22
+ },
23
+ {
24
+ "code": "SMT420",
25
+ "path": "tests/test_process.py",
26
+ "message": "test accesses private production name browserrig.browser.process._active_endpoint",
27
+ "fingerprints": [
28
+ "dfa52a2d2d3e26242ede3e4d0b8cfa66"
29
+ ]
30
+ },
31
+ {
32
+ "code": "SMT420",
33
+ "path": "tests/test_secrets.py",
34
+ "message": "test accesses private production name browserrig.observation.capture._redact",
35
+ "fingerprints": [
36
+ "ed566f1f220074b0fd456472fa517c5c"
37
+ ]
38
+ },
39
+ {
40
+ "code": "SMT420",
41
+ "path": "tests/test_tab_state.py",
42
+ "message": "test accesses private production name browserrig.browser.favicon._media_type",
43
+ "fingerprints": [
44
+ "4778f806842fe755f1da42cf078eaa06"
45
+ ]
46
+ },
47
+ {
48
+ "code": "SMT420",
49
+ "path": "tests/test_terminal.py",
50
+ "message": "test accesses private production name browserrig.terminal._event_record",
51
+ "fingerprints": [
52
+ "a1c9880469f7f66d5e1e8b9a3399f5f4"
53
+ ]
54
+ }
55
+ ]
56
+ }