browser-agent-server 1.0.3__tar.gz → 1.0.4__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 (35) hide show
  1. browser_agent_server-1.0.4/.github/workflows/deploy-ssh.yml +47 -0
  2. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/.github/workflows/release.yml +5 -20
  3. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/CHANGELOG.md +15 -0
  4. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/PKG-INFO +1 -1
  5. browser_agent_server-1.0.4/docs/multi-project-cd.md +99 -0
  6. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/docs/publishing.md +3 -2
  7. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/pyproject.toml +1 -1
  8. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/uv.lock +1 -1
  9. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  10. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  11. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  12. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/.github/workflows/ci.yml +0 -0
  13. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/.gitignore +0 -0
  14. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/AGENTS.md +0 -0
  15. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/LICENSE +0 -0
  16. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/README.md +0 -0
  17. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/docs/api.md +0 -0
  18. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/docs/architecture.md +0 -0
  19. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/docs/deployment.md +0 -0
  20. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/docs/security.md +0 -0
  21. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/docs/troubleshooting.md +0 -0
  22. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/src/browser_agent/__init__.py +0 -0
  23. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/src/browser_agent/chrome.py +0 -0
  24. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/src/browser_agent/cli.py +0 -0
  25. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/src/browser_agent/data/browser-agent.service +0 -0
  26. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/src/browser_agent/server.py +0 -0
  27. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/src/browser_agent/vision_agent.py +0 -0
  28. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/src/browser_agent/x11_input.py +0 -0
  29. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/tests/test_bezier.py +0 -0
  30. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/tests/test_chrome_state_dir.py +0 -0
  31. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/tests/test_cli.py +0 -0
  32. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/tests/test_client.py +0 -0
  33. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/tests/test_cloudflare.py +0 -0
  34. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/tests/test_http_api.py +0 -0
  35. {browser_agent_server-1.0.3 → browser_agent_server-1.0.4}/tests/test_ws_frames.py +0 -0
@@ -0,0 +1,47 @@
1
+ name: deploy-ssh (reusable)
2
+
3
+ # Push-style continuous deployment to self-hosted servers.
4
+ # Caller passes the app name; the server-side dispatcher /usr/local/bin/deploy-tools
5
+ # resolves it via /etc/deploy-tools.d/<app>.conf (install exact version → restart →
6
+ # healthcheck → auto-rollback). See docs/multi-project-cd.md.
7
+ #
8
+ # Caller:
9
+ # deploy:
10
+ # needs: pypi # or your publish job — deploy only what is published
11
+ # uses: vernikr/browser-agent/.github/workflows/deploy-ssh.yml@main
12
+ # with: { app: my-app, tag: ${{ github.ref_name }} }
13
+ # secrets: inherit # DEPLOY_SSH_KEY / DEPLOY_HOST / DEPLOY_USER
14
+
15
+ on:
16
+ workflow_call:
17
+ inputs:
18
+ app:
19
+ required: true
20
+ type: string
21
+ description: App name — must match /etc/deploy-tools.d/<app>.conf on the host
22
+ tag:
23
+ required: true
24
+ type: string
25
+ description: Git tag that triggered the release, e.g. v1.2.3
26
+
27
+ jobs:
28
+ deploy:
29
+ runs-on: ubuntu-latest
30
+ environment:
31
+ name: prod
32
+ steps:
33
+ # Plain ssh (no third-party action): this key is trusted to drive the prod host.
34
+ # Server side it is pinned to the dispatcher via authorized_keys forced command:
35
+ # command="/usr/local/bin/deploy-tools",no-pty,no-port-forwarding,no-agent-forwarding,no-X11-forwarding
36
+ - name: Deploy exact version to production
37
+ env:
38
+ DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
39
+ DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
40
+ DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
41
+ run: |
42
+ mkdir -p ~/.ssh && chmod 700 ~/.ssh
43
+ printf '%s\n' "$DEPLOY_SSH_KEY" > ~/.ssh/ci_deploy_key
44
+ chmod 600 ~/.ssh/ci_deploy_key
45
+ ssh-keyscan -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts 2>/dev/null
46
+ VER="${{ inputs.tag }}"; VER="${VER#v}"
47
+ ssh -i ~/.ssh/ci_deploy_key "$DEPLOY_USER@$DEPLOY_HOST" "deploy ${{ inputs.app }} $VER"
@@ -52,26 +52,11 @@ jobs:
52
52
 
53
53
  deploy:
54
54
  needs: pypi
55
- runs-on: ubuntu-latest
56
- environment:
57
- name: prod
58
- url: http://38.244.152.2:8765/status
59
- steps:
60
- # Plain ssh (no third-party action): this key is trusted to drive the prod host.
61
- # Server side it is pinned to the single command via authorized_keys forced command:
62
- # command="/usr/local/bin/deploy-browser-agent",no-pty,no-port-forwarding,...
63
- - name: Deploy exact version to production
64
- env:
65
- DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
66
- DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
67
- DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
68
- run: |
69
- mkdir -p ~/.ssh && chmod 700 ~/.ssh
70
- printf '%s\n' "$DEPLOY_SSH_KEY" > ~/.ssh/ci_deploy_key
71
- chmod 600 ~/.ssh/ci_deploy_key
72
- ssh-keyscan -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts 2>/dev/null
73
- VER="${GITHUB_REF_NAME#v}"
74
- ssh -i ~/.ssh/ci_deploy_key "$DEPLOY_USER@$DEPLOY_HOST" "deploy $VER"
55
+ uses: ./.github/workflows/deploy-ssh.yml
56
+ with:
57
+ app: browser-agent
58
+ tag: ${{ github.ref_name }}
59
+ secrets: inherit
75
60
 
76
61
  github-release:
77
62
  needs: build
@@ -5,6 +5,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [1.0.4] - 2026-10-10
9
+
10
+ ### Changed
11
+
12
+ - CD generalized for multi-project use: the deploy job now calls the reusable
13
+ workflow `.github/workflows/deploy-ssh.yml`, and the server-side forced
14
+ command became a dispatcher (`deploy <app> <semver>`) driven by
15
+ `/etc/deploy-tools.d/*.conf` — playbook in docs/multi-project-cd.md.
16
+
17
+ ### Added
18
+
19
+ - docs/multi-project-cd.md — how to wire any project on the same server for
20
+ push-style CD in ~20 minutes (checklist + agent prompt).
21
+
22
+
8
23
  ## [1.0.3] - 2026-10-10
9
24
 
10
25
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: browser-agent-server
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: Real headful Chrome on Xvfb with a hardware-level X11 mouse, Cloudflare Turnstile auto-solve and zero-leak CDP. Localhost HTTP API + CLI + Python SDK.
5
5
  Project-URL: Homepage, https://github.com/vernikr/browser-agent
6
6
  Project-URL: Repository, https://github.com/vernikr/browser-agent
@@ -0,0 +1,99 @@
1
+ # Multi-project CD: push every release to production from CI
2
+
3
+ The deploy used for `browser-agent` generalizes to any number of projects on the same
4
+ server. This page is the one-stop playbook — give it (or the prompt at the bottom) to any
5
+ agent to wire up a new project in ~20 minutes.
6
+
7
+ ## Architecture (once per server)
8
+
9
+ ```
10
+ GitHub release.yml (tag push)
11
+ build → publish (OIDC, no tokens)
12
+ → deploy job → reusable workflow deploy-ssh.yml
13
+ └─ ssh <ci-key>@host "deploy <app> <ver>"
14
+ └─ authorized_keys forced command → /usr/local/bin/deploy-tools
15
+ └─ /etc/deploy-tools.d/<app>.conf
16
+ └─ install exact version → restart unit → healthcheck → rollback
17
+ ```
18
+
19
+ - **One CI key serves all projects.** The key is pinned by a forced command to the
20
+ dispatcher; it cannot open a shell, forward ports, or run anything else.
21
+ - **The whitelist of deployable apps is the server itself**: an app exists iff a
22
+ root-owned `/etc/deploy-tools.d/<app>.conf` exists. Unknown names are rejected.
23
+ - **No public endpoint, no firewall changes** — push arrives over the SSH port that is
24
+ already open for admin access.
25
+
26
+ Server-side artifacts (already installed on 38.244.152.2; copy to a new host as-is):
27
+
28
+ - `/usr/local/bin/deploy-tools` — the generic dispatcher (protocol: `deploy <app> <semver>`;
29
+ legacy `deploy <semver>` works while exactly one app is configured).
30
+ - `/etc/deploy-tools.d/browser-agent.conf` — the reference app config.
31
+ - backups under `/root/bak/`.
32
+
33
+ ## Per-project checklist (~20 min)
34
+
35
+ Prerequisites: the project is a package published from CI to a registry with OIDC
36
+ trusted publishing (same one-time registry setup as in `docs/publishing.md`), and it runs
37
+ on the server as a systemd unit with some health signal.
38
+
39
+ 1. **Systemd unit** — the service must come up healthy after `systemctl restart`. Health
40
+ signal: either a JSON endpoint answering `"version": "X.Y.Z"` or a CLI
41
+ `myapp --version`. No JSON endpoint? Put `HEALTH_CMD=...` in the config.
42
+ 2. **Server config** — create `/etc/deploy-tools.d/<app>.conf` (app name: `[a-z0-9-]+`):
43
+
44
+ ```bash
45
+ INSTALLER=uv # uv (Python) | npm-global (Node)
46
+ PKG=<registry package name> # e.g. my-tool-server / @scope/my-tool
47
+ BIN=<executable name> # for uv tools (for --version); optional otherwise
48
+ UNIT=<systemd unit name>
49
+ STATUS_URL=http://127.0.0.1:PORT/status # OR: HEALTH_CMD='...'
50
+ HEALTH_FIELD=version
51
+ ```
52
+
53
+ Test on the host:
54
+
55
+ ```bash
56
+ SSH_ORIGINAL_COMMAND="deploy <app> <current-version>" /usr/local/bin/deploy-tools
57
+ # expect: "already on <ver> and healthy — nothing to do"
58
+ ```
59
+
60
+ 3. **Registry/CI side already solved**: publish from `release.yml` exactly like this repo
61
+ (`pypi`/`npm` job first, so deploy only installs what already exists in the registry).
62
+ 4. **Deploy job** in the project's `release.yml`:
63
+
64
+ ```yaml
65
+ deploy:
66
+ needs: <publish-job>
67
+ uses: vernikr/browser-agent/.github/workflows/deploy-ssh.yml@main
68
+ with:
69
+ app: <app>
70
+ tag: ${{ github.ref_name }}
71
+ secrets: inherit
72
+ ```
73
+
74
+ 5. **Repo secrets** (Settings → Secrets and variables → Actions): `DEPLOY_SSH_KEY`,
75
+ `DEPLOY_HOST`, `DEPLOY_USER` — the same values as in this repo (reusing the same
76
+ single-purpose key across repos is fine and simplifies rotation; rotate by replacing
77
+ the one `authorized_keys` line + the secret values).
78
+ 6. **Smoke-release**: tag `vX.Y.Z+1`, watch the Actions tab — deploy should be green and
79
+ the unit should report the new version on its health endpoint.
80
+
81
+ Failure semantics: unreadable registry → retries; bad health → automatic reinstall of the
82
+ previous version, restart, re-check, and the CI job turns red. Everything is logged in the
83
+ GitHub job — no `journalctl` digging needed for routine failures.
84
+
85
+ ## Agent prompt (copy-paste to configure a new project)
86
+
87
+ > Wire the `<PROJECT>` repo for push-style CD to our production server, following
88
+ > `vernikr/browser-agent/docs/multi-project-cd.md`: (1) on the server create
89
+ > `/etc/deploy-tools.d/<app>.conf` for unit `<UNIT>`, package `<PKG>` (`INSTALLER=uv|npm-global`),
90
+ > health via `STATUS_URL=<...>` or `HEALTH_CMD`, then smoke-test with
91
+ > `SSH_ORIGINAL_COMMAND="deploy <app> <current-version>" /usr/local/bin/deploy-tools`;
92
+ > (2) add a `deploy` job to `<PROJECT>`'s `release.yml` that `needs:` the publish job and
93
+ > calls `vernikr/browser-agent/.github/workflows/deploy-ssh.yml@main` with
94
+ > `with: { app: <app>, tag: github.ref_name }` and `secrets: inherit`;
95
+ > (3) add the repo secrets `DEPLOY_SSH_KEY` / `DEPLOY_HOST` / `DEPLOY_USER` (same values as
96
+ > in `vernikr/browser-agent`); (4) ship a patch release and confirm the deploy job is green
97
+ > and the unit reports the new version. Do not touch other services, firewall, or VPN units
98
+ > on the server; before modifying `authorized_keys` or the dispatcher, back the file up to
99
+ > `/root/bak/`.
@@ -47,5 +47,6 @@ tag version to the production host — no human SSH needed. Design:
47
47
  target version. On healthcheck failure it reinstalls the previous version and restarts again.
48
48
  - Idempotent: redeploying the version already running is a no-op success.
49
49
 
50
- One-time setup on a new host: install `uv` + the package, create/pin the key as above, put the
51
- three secrets into the repo (Settings → Secrets and variables → Actions), done.
50
+ Scaling to more projects on the same server: the forced command now points at a generic
51
+ dispatcher — the full playbook (per-project checklist + an agent prompt) is
52
+ [docs/multi-project-cd.md](multi-project-cd.md).
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "browser-agent-server"
3
- version = "1.0.3"
3
+ version = "1.0.4"
4
4
  description = "Real headful Chrome on Xvfb with a hardware-level X11 mouse, Cloudflare Turnstile auto-solve and zero-leak CDP. Localhost HTTP API + CLI + Python SDK."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -13,7 +13,7 @@ wheels = [
13
13
 
14
14
  [[package]]
15
15
  name = "browser-agent-server"
16
- version = "1.0.3"
16
+ version = "1.0.4"
17
17
  source = { editable = "." }
18
18
  dependencies = [
19
19
  { name = "trafilatura" },