qmpass-test-agent 1.0.10__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 (95) hide show
  1. qmpass_test_agent-1.0.10/LICENSE +15 -0
  2. qmpass_test_agent-1.0.10/PKG-INFO +106 -0
  3. qmpass_test_agent-1.0.10/README.md +433 -0
  4. qmpass_test_agent-1.0.10/README.pypi.md +71 -0
  5. qmpass_test_agent-1.0.10/pyproject.toml +65 -0
  6. qmpass_test_agent-1.0.10/setup.cfg +4 -0
  7. qmpass_test_agent-1.0.10/src/qmpass/__init__.py +8 -0
  8. qmpass_test_agent-1.0.10/src/qmpass/__main__.py +6 -0
  9. qmpass_test_agent-1.0.10/src/qmpass/agent/__init__.py +6 -0
  10. qmpass_test_agent-1.0.10/src/qmpass/agent/artifact_upload.py +355 -0
  11. qmpass_test_agent-1.0.10/src/qmpass/agent/client/__init__.py +26 -0
  12. qmpass_test_agent-1.0.10/src/qmpass/agent/client/connect_errors.py +159 -0
  13. qmpass_test_agent-1.0.10/src/qmpass/agent/client/messages.py +70 -0
  14. qmpass_test_agent-1.0.10/src/qmpass/agent/client/websocket.py +946 -0
  15. qmpass_test_agent-1.0.10/src/qmpass/agent/doctor.py +216 -0
  16. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/__init__.py +82 -0
  17. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/core/__init__.py +15 -0
  18. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/core/controller.py +558 -0
  19. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/core/models.py +27 -0
  20. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/core/orchestrator.py +720 -0
  21. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/core/paths.py +9 -0
  22. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/core/robot_gen.py +50 -0
  23. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/mapping/__init__.py +13 -0
  24. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/mapping/mapper.py +254 -0
  25. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/protocol/__init__.py +298 -0
  26. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/adapters/angular.js +29 -0
  27. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/adapters/react.js +32 -0
  28. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/adapters/salesforce.js +27 -0
  29. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/adapters/standard.js +24 -0
  30. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/assertPick.js +507 -0
  31. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/content.js +123 -0
  32. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/detector.js +86 -0
  33. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/events.js +173 -0
  34. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/highlighter.js +159 -0
  35. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/rawEventCollector.js +247 -0
  36. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/recorder-engine/actionDetector.js +74 -0
  37. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/recorder-engine/config.js +33 -0
  38. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/recorder-engine/eventAggregator.js +177 -0
  39. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/recorder-engine/eventNormalizer.js +122 -0
  40. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/recorder-engine/keywordBuilder.js +116 -0
  41. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/selector.js +136 -0
  42. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/selectorBase.js +200 -0
  43. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/surfaceObserver.js +532 -0
  44. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/ui/qmpass-recorder-widget.js +8691 -0
  45. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/widget_adapter.js +329 -0
  46. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/content-script/widget_host.js +86 -0
  47. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/extension/background.js +768 -0
  48. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/icon.png +0 -0
  49. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/icon128.png +0 -0
  50. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/icon16.png +0 -0
  51. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/icon48.png +0 -0
  52. qmpass_test_agent-1.0.10/src/qmpass/agent/recorder/sidebar/manifest.json +83 -0
  53. qmpass_test_agent-1.0.10/src/qmpass/agent/robot/__init__.py +9 -0
  54. qmpass_test_agent-1.0.10/src/qmpass/agent/robot/data_files.py +126 -0
  55. qmpass_test_agent-1.0.10/src/qmpass/agent/robot/models.py +193 -0
  56. qmpass_test_agent-1.0.10/src/qmpass/agent/robot/paths.py +10 -0
  57. qmpass_test_agent-1.0.10/src/qmpass/agent/robot/redact.py +111 -0
  58. qmpass_test_agent-1.0.10/src/qmpass/agent/robot/result_mapper.py +142 -0
  59. qmpass_test_agent-1.0.10/src/qmpass/agent/robot/self_healing_listener.py +57 -0
  60. qmpass_test_agent-1.0.10/src/qmpass/agent/robot/suite_writer.py +80 -0
  61. qmpass_test_agent-1.0.10/src/qmpass/agent/run_summary.py +107 -0
  62. qmpass_test_agent-1.0.10/src/qmpass/agent/runner/__init__.py +12 -0
  63. qmpass_test_agent-1.0.10/src/qmpass/agent/runner/cancel.py +157 -0
  64. qmpass_test_agent-1.0.10/src/qmpass/agent/runner/execute.py +315 -0
  65. qmpass_test_agent-1.0.10/src/qmpass/agent/runner/result_build.py +249 -0
  66. qmpass_test_agent-1.0.10/src/qmpass/agent/runner/robot_process.py +372 -0
  67. qmpass_test_agent-1.0.10/src/qmpass/agent/runner/task_runner.py +64 -0
  68. qmpass_test_agent-1.0.10/src/qmpass/agent/runner/work_dir.py +187 -0
  69. qmpass_test_agent-1.0.10/src/qmpass/agent/runtime.py +104 -0
  70. qmpass_test_agent-1.0.10/src/qmpass/agent/system_info.py +86 -0
  71. qmpass_test_agent-1.0.10/src/qmpass/agent/tls.py +42 -0
  72. qmpass_test_agent-1.0.10/src/qmpass/agent/update_check.py +81 -0
  73. qmpass_test_agent-1.0.10/src/qmpass/cli.py +290 -0
  74. qmpass_test_agent-1.0.10/src/qmpass/config/__init__.py +5 -0
  75. qmpass_test_agent-1.0.10/src/qmpass/config/settings.py +211 -0
  76. qmpass_test_agent-1.0.10/src/qmpass/desktop.py +101 -0
  77. qmpass_test_agent-1.0.10/src/qmpass/exit_codes.py +16 -0
  78. qmpass_test_agent-1.0.10/src/qmpass/logging_setup.py +199 -0
  79. qmpass_test_agent-1.0.10/src/qmpass_test_agent.egg-info/PKG-INFO +106 -0
  80. qmpass_test_agent-1.0.10/src/qmpass_test_agent.egg-info/SOURCES.txt +93 -0
  81. qmpass_test_agent-1.0.10/src/qmpass_test_agent.egg-info/dependency_links.txt +1 -0
  82. qmpass_test_agent-1.0.10/src/qmpass_test_agent.egg-info/entry_points.txt +3 -0
  83. qmpass_test_agent-1.0.10/src/qmpass_test_agent.egg-info/requires.txt +29 -0
  84. qmpass_test_agent-1.0.10/src/qmpass_test_agent.egg-info/top_level.txt +1 -0
  85. qmpass_test_agent-1.0.10/tests/test_cli_version.py +14 -0
  86. qmpass_test_agent-1.0.10/tests/test_config.py +85 -0
  87. qmpass_test_agent-1.0.10/tests/test_doctor.py +82 -0
  88. qmpass_test_agent-1.0.10/tests/test_logging_and_messages.py +167 -0
  89. qmpass_test_agent-1.0.10/tests/test_messages_payload.py +95 -0
  90. qmpass_test_agent-1.0.10/tests/test_recorder_mapper.py +35 -0
  91. qmpass_test_agent-1.0.10/tests/test_tls_and_platform_url.py +66 -0
  92. qmpass_test_agent-1.0.10/tests/test_update_check.py +55 -0
  93. qmpass_test_agent-1.0.10/tests/test_version.py +10 -0
  94. qmpass_test_agent-1.0.10/tests/test_wheel_contents.py +40 -0
  95. qmpass_test_agent-1.0.10/tests/test_wheel_no_emit.py +29 -0
@@ -0,0 +1,15 @@
1
+ Qmpass Test Agent
2
+ Copyright (c) 2026 Qmpass. All rights reserved.
3
+
4
+ This software is proprietary. It is made available solely for use with a Qmpass subscription, to
5
+ connect machines you control to the Qmpass platform and run tests on them.
6
+
7
+ You may install and run unmodified copies of this software for that purpose. You may not modify,
8
+ redistribute, sublicense, sell, reverse engineer (except where the law permits it), or use this
9
+ software, or any part of it, to build a competing product or service.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. IN NO EVENT
12
+ SHALL QMPASS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY ARISING FROM THE USE OF THE
13
+ SOFTWARE.
14
+
15
+ Use of the software is also subject to the Qmpass terms of service.
@@ -0,0 +1,106 @@
1
+ Metadata-Version: 2.4
2
+ Name: qmpass-test-agent
3
+ Version: 1.0.10
4
+ Summary: Run your Qmpass automated tests on your own machines, securely connected to your Jira projects.
5
+ Author: Qmpass
6
+ License-Expression: LicenseRef-Proprietary
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: websockets==15.0.1
11
+ Requires-Dist: requests==2.34.2
12
+ Requires-Dist: psutil==6.1.1
13
+ Requires-Dist: truststore==0.10.4
14
+ Requires-Dist: robotframework==7.4.2
15
+ Requires-Dist: robotframework-browser==19.10.1
16
+ Requires-Dist: robotframework-requests==0.9.7
17
+ Requires-Dist: robotframework-datadriver==1.11.2
18
+ Requires-Dist: robotframework-faker==6.0.0
19
+ Requires-Dist: robotframework-databaselibrary==2.3.1
20
+ Provides-Extra: postgres
21
+ Requires-Dist: psycopg2-binary==2.9.10; extra == "postgres"
22
+ Provides-Extra: mysql
23
+ Requires-Dist: pymysql==1.1.1; extra == "mysql"
24
+ Provides-Extra: salesforce
25
+ Requires-Dist: rpaframework==33.0.1; extra == "salesforce"
26
+ Provides-Extra: desktop
27
+ Requires-Dist: pystray==0.19.5; extra == "desktop"
28
+ Requires-Dist: Pillow==11.3.0; extra == "desktop"
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
31
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
32
+ Requires-Dist: ruff>=0.6.0; extra == "dev"
33
+ Requires-Dist: pip-tools>=7.0.0; extra == "dev"
34
+ Dynamic: license-file
35
+
36
+ # Qmpass Test Agent
37
+
38
+ Run your [Qmpass](https://qmpass.ai) automated tests on your own laptops, servers or virtual
39
+ machines — faster feedback, safer releases, and full control over your test environments.
40
+
41
+ ## Requirements
42
+
43
+ - Python 3.10 or newer
44
+ - Node.js 18 or newer (for Browser tests)
45
+ - An agent token from Qmpass: **Project settings → Agents → Add agent**
46
+
47
+ ## Install
48
+
49
+ ```bash
50
+ pipx install qmpass-test-agent # or: pipx install "qmpass-test-agent[postgres]" / [mysql] / [salesforce]
51
+ qmpass-agent setup # one time: installs the browser used by Browser tests
52
+ qmpass-agent doctor # checks everything below, with a fix for each problem
53
+ ```
54
+
55
+ `doctor` checks Python, Robot, Node.js and Chromium, your `QMPASS_TOKEN` / `QMPASS_URL`, that
56
+ Qmpass can be reached, and that the token is accepted — without starting a session, so it's safe to
57
+ run while an agent is already running.
58
+
59
+ Optional add-ons, only needed if your tests use them:
60
+
61
+ | Add-on | Install | For tests that |
62
+ |---|---|---|
63
+ | `postgres` | `pipx install "qmpass-test-agent[postgres]"` | query a PostgreSQL database |
64
+ | `mysql` | `pipx install "qmpass-test-agent[mysql]"` | query a MySQL / MariaDB database |
65
+ | `salesforce` | `pipx install "qmpass-test-agent[salesforce]"` | work with Salesforce (large install) |
66
+
67
+ No pipx yet? `brew install pipx` (macOS), `python3 -m pip install --user pipx` (Windows / Linux),
68
+ then `pipx ensurepath`.
69
+
70
+ ## Run
71
+
72
+ Copy the command shown with your agent token in Qmpass, or:
73
+
74
+ ```bash
75
+ export QMPASS_TOKEN=qmp_agent_…
76
+ qmpass-agent run
77
+ ```
78
+
79
+ The agent connects to `https://api.qmpass.ai` (set `QMPASS_URL` for other deployments), waits for
80
+ jobs, and logs one line when each run starts and finishes.
81
+
82
+ Useful options: `--worker N` (parallel jobs, up to 5), `--log-file PATH`, `--log-format json`,
83
+ `--log-level DEBUG`. Run `qmpass-agent --help` for all commands.
84
+
85
+ ## Update
86
+
87
+ ```bash
88
+ pipx upgrade qmpass-test-agent
89
+ ```
90
+
91
+ When a newer version is available, `qmpass-agent run` says so in one line at startup (and `doctor`
92
+ shows it). The agent never updates itself. Set `QMPASS_AGENT_UPDATE_CHECK=0` to turn the check off.
93
+
94
+ ## Exit codes
95
+
96
+ | Code | Meaning |
97
+ |------|---------|
98
+ | 0 | Stopped normally |
99
+ | 2 | Configuration error |
100
+ | 3 | Refused by the platform (invalid or expired token, agent disabled) — the log says which |
101
+ | 4 | Agent too old — run `pipx upgrade qmpass-test-agent` |
102
+ | 5 | A prerequisite is missing (e.g. Node.js) — run `qmpass-agent setup` |
103
+
104
+ ## License
105
+
106
+ Proprietary — for use with a Qmpass subscription. See `LICENSE`.
@@ -0,0 +1,433 @@
1
+ # Qmpass Test Agent
2
+
3
+ Python agent that connects to the **Qmpass platform gateway** via **WebSocket** and executes test jobs locally. Package namespace: `qmpass.*`.
4
+
5
+ Product Robot suite **codegen** is platform-side (`qmpass-robot-compiler`). This agent writes precompiled `robotSuites`, runs Robot Framework, and publishes results.
6
+
7
+ ## How to run the agent
8
+
9
+ | Path | When to use |
10
+ |------|-------------|
11
+ | **pipx** (laptops, from PyPI) | `pipx install qmpass-test-agent`, `qmpass-agent setup` (Browser / Chromium), `qmpass-agent doctor` (checks everything) — see `README.pypi.md`, the PyPI page. |
12
+ | **Docker** (preferred for shared runners / CI) | Isolated image; no host Python. See [Deployment Options](#deployment-options). |
13
+ | **Local install in a dedicated venv** | QA laptops that must use **local browsers** (Robot Browser / Playwright on this machine). |
14
+
15
+ Do **not** install into the system Python or rely on a bare `python` on `PATH`. On many Macs that points at Python 2.7 and Robot will fail with `No module named Browser`. Always use an isolated environment so `qmpass-agent` and Robot share the same interpreter.
16
+
17
+ ## Prerequisites
18
+
19
+ - **Python 3.10+** (3.11 or 3.12 recommended) — used only to create the venv below
20
+ - **Node.js ≥ 18** on `PATH` (required by Robot Framework Browser / Playwright)
21
+ - **QMPASS_TOKEN** (from the Qmpass UI when creating an agent)
22
+ - **QMPASS_URL** (optional; defaults to `https://api.qmpass.ai`): set it for dev / staging / other deployments — the URL is shown with your agent token in Qmpass (Project settings → Agents → **Copy command**); plain `http://` only for a local stack such as `http://localhost:30085`
23
+
24
+ ## Quick Start (local browsers — isolated `qmpass-agent` env)
25
+
26
+ Full path for a laptop that needs local Browser/Playwright. Create a **new** venv named for Qmpass, activate it, install into that env, then run. Do not use system Python.
27
+
28
+ You can create the venv from **any directory**. You only need the agent repo checkout when installing from source (`pip install -e .`). Once the agent is published as a package, install by name — no clone required.
29
+
30
+ ### macOS / Linux — first-time setup
31
+
32
+ ```bash
33
+ # 1) Confirm a real Python 3.10+ (do not use bare `python` if it is 2.x)
34
+ python3 --version
35
+
36
+ # 2) Create a dedicated env (any working directory is fine)
37
+ python3 -m venv ~/.venvs/qmpass-agent
38
+
39
+ # 3) Activate it (required for all following steps)
40
+ source ~/.venvs/qmpass-agent/bin/activate
41
+ # Prompt should show (qmpass-agent); `which python` → ~/.venvs/qmpass-agent/bin/python
42
+
43
+ # 4) Upgrade pip inside the venv only
44
+ python -m pip install --upgrade pip setuptools wheel
45
+
46
+ # 5) Install agent + Robot / Browser deps into this env
47
+ #
48
+ # From a source checkout (current / development):
49
+ cd /path/to/qmpass-test-agent
50
+ pip install -e .
51
+ #
52
+ # Later, when distributed as a package (no repo needed):
53
+ # pip install qmpass-test-agent
54
+ #
55
+ # Optional tray app (same env):
56
+ # pip install -e ".[desktop]"
57
+ # # or: pip install "qmpass-test-agent[desktop]"
58
+ # Salesforce REST (RPA.Salesforce / rpaframework) — large optional install:
59
+ # pip install -e ".[salesforce]"
60
+ # # or: pip install "qmpass-test-agent[salesforce]"
61
+
62
+ # 6) Install Playwright browsers used by Robot Framework Browser (same env)
63
+ python -m Browser.entry init
64
+
65
+ # 7) Configure and start (venv still activated)
66
+ export QMPASS_TOKEN="qmp_agent_xxxx"
67
+ # export QMPASS_URL="http://localhost:30085" # only off production; default is https://api.qmpass.ai
68
+ qmpass-agent run
69
+ ```
70
+
71
+ ### macOS / Linux — every later session
72
+
73
+ ```bash
74
+ source ~/.venvs/qmpass-agent/bin/activate
75
+ export QMPASS_TOKEN="qmp_agent_xxxx"
76
+ qmpass-agent run
77
+ ```
78
+
79
+ (No need to `cd` into the repo unless you are reinstalling or developing.)
80
+
81
+ ### Windows (PowerShell) — first-time setup
82
+
83
+ ```powershell
84
+ py -3.11 --version
85
+ py -3.11 -m venv $HOME\venvs\qmpass-agent
86
+ $HOME\venvs\qmpass-agent\Scripts\Activate.ps1
87
+
88
+ python -m pip install --upgrade pip setuptools wheel
89
+
90
+ # From source (current):
91
+ cd C:\path\to\qmpass-test-agent
92
+ pip install -e .
93
+ # Packaged release (later): pip install qmpass-test-agent
94
+
95
+ python -m Browser.entry init
96
+
97
+ $env:QMPASS_TOKEN = "qmp_agent_xxxx"
98
+ qmpass-agent run
99
+ ```
100
+
101
+ ### Verify (optional)
102
+
103
+ With `qmpass-agent` venv activated:
104
+
105
+ ```bash
106
+ which python # .../qmpass-agent/bin/python (not system 2.7)
107
+ which qmpass-agent # .../qmpass-agent/bin/qmpass-agent
108
+ python -c "import Browser, robot; print('ok', robot.__version__)"
109
+ node --version # >= 18
110
+ ```
111
+
112
+ Robot uses the same interpreter as the agent (`sys.executable`). You normally do **not** set `QMPASS_AGENT_PYTHON_BIN` when running from this venv.
113
+
114
+ ## Configuration
115
+
116
+ Contributor conventions: see **[AGENTS.md](./AGENTS.md)** (includes how to add platform library adapters: Browser, RequestsLibrary, DatabaseLibrary, …).
117
+
118
+ | Variable | Required | Description |
119
+ | --------------------------- | -------- | --------------------------------------------------------------------------- |
120
+ | QMPASS_TOKEN | Yes | Token shown once when creating an agent in the UI |
121
+ | QMPASS_URL | No | Base URL of the gateway (shown with the agent token); default `https://api.qmpass.ai`. Must be `https://` except for localhost / 127.0.0.1 / host.docker.internal |
122
+ | MAX_PARALLEL_JOBS | No | Same as `--worker` / `--concurrency` when the CLI flag is omitted (default **1**, max **5**) |
123
+ | QMPASS_AGENT_KEEP_ROBOT_ARTIFACTS | No | If `true`, keep per-job temp dirs with Robot logs instead of deleting them |
124
+ | QMPASS_AGENT_RUN_ROOT | No | Base directory for per-job run artifacts (default: system temp dir) |
125
+ | QMPASS_AGENT_LAST_RUN_DIR | No | Fixed dir for local debug (`--worker=1` only). GATE: keeps `{target}.zip` per target |
126
+ | QMPASS_AGENT_PYTHON_BIN | No | Python for `python -m robot` (default: agent `sys.executable`) |
127
+ | QMPASS_AGENT_UPLOAD_ARTIFACTS | No | If `true`, upload Robot artifacts for DRY runs (GATE always uploads) |
128
+ | QMPASS_AGENT_ARTIFACT_MAX_SIZE_MB | No | Max per-file size (MB) for uploads (default 50) |
129
+ | QMPASS_AGENT_ROBOT_TIMEOUT_SEC | No | Default Robot timeout seconds when payload has no `timeoutMs` (default 600) |
130
+ | QMPASS_AGENT_ROBOT_EXIT_ON_FAILURE | No | Pass `--exitonfailure` to Robot |
131
+ | QMPASS_AGENT_ROBOT_INCLUDE_STEPS | No | Enrich results with `robot.steps[]` |
132
+
133
+ **Breaking change:** older env prefixes from earlier agent builds are no longer read. Use `QMPASS_AGENT_*` only.
134
+
135
+ The agent connects to `QMPASS_URL` over WebSocket at `/api/v1/agent/ws`, sending its token as `Authorization: Bearer <QMPASS_TOKEN>` (never in the URL). Jobs are pushed by the platform over the socket; results are sent back the same way. If the connection drops, running jobs carry on: the agent reconnects (backoff 2–30s, reset after a good connection) and sends any results that finished meanwhile.
136
+
137
+ ## Deployment Options
138
+
139
+ - **Docker** (recommended for shared runners / CI): build from `docker/Dockerfile` using frozen locks under `requirements/` (see [`requirements/README.md`](./requirements/README.md)).
140
+
141
+ ```bash
142
+ # Base image (default) — Browser / Requests / Database / DataDriver / Faker
143
+ docker build -f docker/Dockerfile -t qmpass-test-agent:base .
144
+
145
+ # Salesforce image — base + RPA.Salesforce (rpaframework)
146
+ docker build -f docker/Dockerfile --build-arg AGENT_VARIANT=salesforce -t qmpass-test-agent:salesforce .
147
+
148
+ docker run --rm -e QMPASS_TOKEN=… -e QMPASS_URL=… qmpass-test-agent:base
149
+ # Includes Node.js and Playwright Chromium; Browser environments must run headless in containers.
150
+ ```
151
+
152
+ Runs as non-root. Laptop/dev can still `pip install -e .` without the lock; Docker/CI **must** use the lock files.
153
+
154
+ - **CLI (venv)**: follow [Quick Start](#quick-start-local-browsers--isolated-qmpass-agent-env). Ctrl+C triggers graceful disconnect.
155
+ - **Desktop**: `qmpass-agent desktop` or `qmpass-agent-desktop` — tray app; install with `pip install -e ".[desktop]"` **inside the same venv**.
156
+
157
+ ## Logs and exit codes
158
+
159
+ The agent logs one line per event that matters: a startup summary, connection changes, and one
160
+ line when each run starts and finishes (result, duration, tests, artifacts). Robot's own console
161
+ output and the platform protocol are at `DEBUG`.
162
+
163
+ ```
164
+ 2026-10-05T09:12:03+05:30 INFO Connected as agent "QA-Laptop-01" (project DEMO). Waiting for jobs.
165
+ 2026-10-05T09:14:10+05:30 INFO [run 3f2a1c9e] Run 3f2a1c9e started: runbook "Checkout smoke" on "Staging" (timeout 10m)
166
+ 2026-10-05T09:14:53+05:30 INFO [run 3f2a1c9e] Run 3f2a1c9e passed in 43s: 12/12 tests passed · 5 artifacts uploaded (2.1 MB)
167
+ ```
168
+
169
+ | Option | Env var | Default |
170
+ |--------|---------|---------|
171
+ | `--log-level DEBUG\|INFO\|WARNING\|ERROR` | `QMPASS_AGENT_LOG_LEVEL` | `INFO` |
172
+ | `--log-file PATH` (rotated, 10 MB × 5) | `QMPASS_AGENT_LOG_FILE` | none (desktop app: `~/Library/Logs/Qmpass/agent.log`, `%LOCALAPPDATA%\Qmpass\Logs\agent.log`, `~/.local/state/qmpass/agent.log`) |
173
+ | `--log-format text\|json` (JSON: one object per line) | `QMPASS_AGENT_LOG_FORMAT` | `text` |
174
+
175
+ Agent and project tokens, presigned URL signatures and the current runs' secret values are masked
176
+ (`********`) in every log line.
177
+
178
+ | Exit code | Meaning |
179
+ |-----------|---------|
180
+ | 0 | Stopped normally |
181
+ | 2 | Configuration error (e.g. `QMPASS_URL` invalid) |
182
+ | 3 | The platform refused this agent: invalid or expired token, or agent disabled — the log says which |
183
+ | 4 | Agent too old for the platform — update `qmpass-test-agent` |
184
+ | 5 | A prerequisite is missing (e.g. Node.js) |
185
+
186
+ Network problems, a platform restart or another process using the token are retried (the reason is
187
+ logged once, then a reminder every 5 minutes).
188
+
189
+ ## Security
190
+
191
+ - **Environment secrets** (database / API / Salesforce passwords and tokens) never appear in the
192
+ suite: it reads them as `%{QMPASS_…}`, and the agent passes their values to Robot only as
193
+ environment variables. After each run their values are masked (`********`) in `output.xml` and the
194
+ text artifacts, and `log.html` / `report.html` are rebuilt from the masked output before upload.
195
+ - **The agent token** never reaches Robot: runbooks can't read `%{QMPASS_TOKEN}`.
196
+ - **`QMPASS_URL`** defaults to production (`https://api.qmpass.ai`); a token only works on the platform
197
+ that issued it, so dev / staging agents set it. It must be `https://` (plain `http://` only for
198
+ localhost / `host.docker.internal`).
199
+ - **TLS** is verified against the operating system's trust store (macOS Keychain, Windows store,
200
+ `/etc/ssl`), so company proxies with their own root CA work and python.org Python needs no
201
+ "Install Certificates" step. `SSL_CERT_FILE` / `REQUESTS_CA_BUNDLE` override it; certifi is the
202
+ fallback. Verification is never disabled.
203
+ - **Run folders** under `QMPASS_AGENT_RUN_ROOT` are private to the agent's user (`0700`).
204
+ - **The recorder socket** (`127.0.0.1`) accepts only the Qmpass browser extension, not web pages.
205
+ - **Version:** the platform refuses agents older than its minimum (currently 1.0.0); update the agent
206
+ when it says so.
207
+
208
+ ## CLI Commands
209
+
210
+ | Command | Description |
211
+ | ----------------------- | -------------------------------------------------------- |
212
+ | `qmpass-agent run` | Run agent (WebSocket connection; default **1** concurrent checkpoint job) |
213
+ | `qmpass-agent run --worker=N` | Up to **N** concurrent checkpoint jobs (max **5**; aliases `--workers`, `--concurrency`) |
214
+ | `qmpass-agent run-robot` | Run a `.robot` file using the agent's Python (libraries resolve) |
215
+ | `qmpass-agent desktop` | Launch desktop tray application |
216
+ | `qmpass-agent version` | Print version |
217
+
218
+ ### Running generated .robot files
219
+
220
+ At runtime, each job is executed in its **own temporary directory** with a predictable structure.
221
+
222
+ - **Root directory**:
223
+ - Defaults to the system temp directory from `tempfile.gettempdir()` (e.g. `/tmp`).
224
+ - Can be overridden via `QMPASS_AGENT_RUN_ROOT`.
225
+ - **Per-job structure**:
226
+
227
+ ```text
228
+ <QMPASS_AGENT_RUN_ROOT or /tmp>/qmpass/<scriptId>/<correlationId>/
229
+ runbook.robot
230
+ logs/
231
+ output.xml
232
+ log.html
233
+ report.html
234
+ playwright-log.txt
235
+ ...
236
+ ```
237
+
238
+ The agent:
239
+
240
+ - Builds `runbook.robot` under the per-job directory.
241
+ - Runs `<agent-python> -m robot --outputdir <job-dir>/logs <job-dir>/runbook.robot`.
242
+ - Parses `<job-dir>/logs/output.xml` into the job result.
243
+
244
+ By default, the per-job directory is **deleted** after the result is built.
245
+
246
+ This uses the agent's Python environment so `Browser` and `RequestsLibrary` resolve correctly. Extra args are passed through to Robot Framework:
247
+
248
+ ```bash
249
+ qmpass-agent run-robot runbook.robot --loglevel DEBUG
250
+ ```
251
+
252
+ If you want to inspect full Robot artifacts (log.html, output.xml, report.html, playwright-log.txt) per job, set:
253
+
254
+ ```bash
255
+ export QMPASS_AGENT_KEEP_ROBOT_ARTIFACTS=true
256
+ # optional root (still creates qmpass/<scriptId>/<correlationId>/):
257
+ export QMPASS_AGENT_RUN_ROOT=/Users/mehul/qmpass-runs
258
+ ```
259
+
260
+ For **local debugging of only the latest run** (same path every time):
261
+
262
+ ```bash
263
+ export QMPASS_AGENT_LAST_RUN_DIR=/Users/mehul/qmpass-runs/last
264
+ ```
265
+
266
+ For **DRY / non-GATE** jobs, `$QMPASS_AGENT_LAST_RUN_DIR` keeps `runbook.robot` and `logs/` after each run (overwrites the previous job). `QMPASS_AGENT_LAST_RUN_DIR` implies keep (no cleanup).
267
+
268
+ For **GATE multi-target** runs (e.g. Chrome + Firefox), each target produces `{target}.zip` under the same directory. Staging `runbook.robot` and `logs/` are removed after each target zip is built — only the zips (plus `.qmpass-last-run-scope`) remain. Sibling target zips are kept until you start a different checkpoint.
269
+
270
+ In that case, the per-job temp directories are not removed and can be inspected manually.
271
+ S3 upload still runs for GATE (and for DRY when `QMPASS_AGENT_UPLOAD_ARTIFACTS=true`); keep mode
272
+ only skips deleting the local work dir after upload.
273
+
274
+ ## Robot Execution Result Schema
275
+
276
+ When a job is executed via Robot Framework, `task_runner.execute(job)` returns a JSON-like structure that the platform uses to update execution state.
277
+
278
+ - **Top-level shape**:
279
+
280
+ ```jsonc
281
+ {
282
+ "status": "PASS", // overall result: PASS / FAIL
283
+ "id": "6f99-...", // correlationId from TASK_REQUEST
284
+ "jobId": "job-123", // optional, from execution
285
+ "executionId": "exec-123", // optional, from execution
286
+ "executionTestCaseId": "etc-1", // optional, from execution
287
+ "runType": "DRY", // NORMAL / DRY / ...
288
+ "robot": { ... } // Robot-specific details
289
+ }
290
+ ```
291
+
292
+ - **`robot` envelope**:
293
+
294
+ ```jsonc
295
+ "robot": {
296
+ "status": "PASS", // suite-level PASS / FAIL
297
+ "startTime": "2026-03-03T12:00:01.636578",
298
+ "elapsedMs": 3336, // suite elapsed time in milliseconds
299
+ "statistics": {
300
+ "total": { "pass": 1, "fail": 0, "skip": 0 }
301
+ },
302
+ "tests": [
303
+ {
304
+ "id": "s1-t1",
305
+ "name": "Script 698cafa474778f72c4c09134",
306
+ "status": "PASS",
307
+ "startTime": "2026-03-03T12:00:03.483515",
308
+ "elapsedMs": 1455
309
+ }
310
+ ],
311
+ "errors": [
312
+ {
313
+ "time": "2026-03-03T12:00:04.000000",
314
+ "level": "ERROR",
315
+ "text": "Suite setup failed: ..."
316
+ }
317
+ ],
318
+ "robotExitCode": 0 // exit code from the Robot subprocess
319
+ }
320
+ ```
321
+
322
+ - **Notes**:
323
+ - `status` at the top level mirrors `robot.status`. The platform uses this to decide if the job is considered successful.
324
+ - `tests[*]` maps directly to `<test>` elements in `output.xml`. Today there is one test per script: `Script <scriptId>`.
325
+ - `errors` contains suite-level errors from the `<errors>` block in `output.xml`.
326
+ - When `QMPASS_AGENT_ROBOT_INCLUDE_STEPS` is enabled, an additional `robot.steps[]` collection is populated with flattened step-level data (keywords and control structures) for debugging/analytics.
327
+ - Additional optional fields (for example, richer step-level data) will be added under `robot` to avoid breaking existing consumers.
328
+
329
+ ## Startup & Preflight Checks
330
+
331
+ On startup (`qmpass-agent run`), the agent performs a **preflight environment check** before connecting to the platform:
332
+
333
+ - **Node.js / Browser**:
334
+ - Runs `node --version` and validates that:
335
+ - `node` is available in `PATH`.
336
+ - The major version is **≥ 18**.
337
+ - If the check fails, the agent logs a clear error like:
338
+ - `Browser library requires Node.js >= 18, but found 16.20.2. Agent cannot start.`
339
+ - In this case the agent **exits with code 1** and does not go ONLINE.
340
+
341
+ At **job execution time**, an additional per-job check is performed:
342
+
343
+ - If Node.js is not suitable when a job is received:
344
+ - The Robot subprocess is **not** started.
345
+ - The job result contains:
346
+ - `status: "FAIL"`
347
+ - `robot.error` with a human-readable message explaining the Node/Browsers requirement issue.
348
+
349
+ These checks are designed to:
350
+
351
+ - Fail fast on obvious misconfiguration at startup.
352
+ - Prevent individual jobs from hanging when Browser/Playwright cannot be started.
353
+
354
+ ## Package Structure
355
+
356
+ ```
357
+ qmpass/
358
+ __init__.py # __version__, Settings, run
359
+ cli.py # CLI entry (run, desktop, version)
360
+ desktop.py # Tray app (optional)
361
+ __main__.py # python -m qmpass
362
+ agent/
363
+ runtime.py # Process bootstrap (signals + WS loop)
364
+ system_info.py # x-agent-info handshake
365
+ client/ # WebSocket connection
366
+ runner/ # Job execution (execute, robot_process, work_dir, cancel)
367
+ robot/ # Suite generation + adapters
368
+ recorder/ # Recording / playback
369
+ artifact_upload.py
370
+ config/
371
+ settings.py # Settings SSOT from env
372
+ ```
373
+
374
+ ## Recorder extension
375
+
376
+ The recorder's browser extension ships inside the package at `src/qmpass/agent/recorder/sidebar/`
377
+ (package data, so pip / pipx / Docker installs all have it). The in-page widget
378
+ (`content-script/ui/qmpass-recorder-widget.js`) is built in **qmpass-test-recorder-web** with
379
+ `npm run build:widget`, which copies it there; commit the rebuilt file with the change.
380
+
381
+ ## Releasing to PyPI
382
+
383
+ PyPI never accepts the same version twice, so **any** change that reaches the package, including
384
+ only the PyPI page (`README.pypi.md`) or `pyproject.toml` metadata, needs a new version.
385
+
386
+ **1. Bump the version** (semver: patch for fixes and docs, minor for new features, major for
387
+ breaking changes such as renamed env vars or CLI flags). It lives in two places, which must match:
388
+
389
+ - `pyproject.toml` → `version = "X.Y.Z"`
390
+ - `src/qmpass/__init__.py` → `__version__ = "X.Y.Z"` (shown by `qmpass-agent --version` and at startup)
391
+
392
+ **2. Check, then build a clean wheel**
393
+
394
+ ```bash
395
+ source ~/.venvs/qmpass-agent/bin/activate
396
+ python -m pip install build twine
397
+ ruff check src tests && pytest -q
398
+ rm -rf build dist src/*.egg-info # stale files would end up in the wheel
399
+ python -m build --wheel # wheel only: no tests or repo files in the release
400
+ twine check dist/* # validates metadata and that README.pypi.md renders
401
+ ```
402
+
403
+ **3. Smoke-test the wheel in a throwaway env**
404
+
405
+ ```bash
406
+ python3 -m venv /tmp/qmpass-release && /tmp/qmpass-release/bin/pip install dist/*.whl
407
+ /tmp/qmpass-release/bin/qmpass-agent --version # prints X.Y.Z
408
+ /tmp/qmpass-release/bin/qmpass-agent doctor # with QMPASS_TOKEN set
409
+ rm -rf /tmp/qmpass-release
410
+ ```
411
+
412
+ **4. Commit, then upload**
413
+
414
+ ```bash
415
+ git commit -am "Release X.Y.Z: <what changed>"
416
+ twine upload dist/* # username __token__, password = your PyPI API token
417
+ ```
418
+
419
+ Check https://pypi.org/project/qmpass-test-agent/ shows the new version, then
420
+ `pipx upgrade qmpass-test-agent` (or `pip install -U qmpass-test-agent`). Running agents mention the
421
+ new version at startup (see `update_check.py`).
422
+
423
+ ## Development
424
+
425
+ Use **VS Code** (or any editor). The repo ignores `.idea/` and `.vscode/` so local IDE settings stay out of git.
426
+
427
+ ```bash
428
+ # Prefer the same dedicated venv as local install
429
+ source ~/.venvs/qmpass-agent/bin/activate
430
+ pip install -e ".[dev]"
431
+ pytest
432
+ ruff check src tests
433
+ ```
@@ -0,0 +1,71 @@
1
+ # Qmpass Test Agent
2
+
3
+ Run your [Qmpass](https://qmpass.ai) automated tests on your own laptops, servers or virtual
4
+ machines — faster feedback, safer releases, and full control over your test environments.
5
+
6
+ ## Requirements
7
+
8
+ - Python 3.10 or newer
9
+ - Node.js 18 or newer (for Browser tests)
10
+ - An agent token from Qmpass: **Project settings → Agents → Add agent**
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pipx install qmpass-test-agent # or: pipx install "qmpass-test-agent[postgres]" / [mysql] / [salesforce]
16
+ qmpass-agent setup # one time: installs the browser used by Browser tests
17
+ qmpass-agent doctor # checks everything below, with a fix for each problem
18
+ ```
19
+
20
+ `doctor` checks Python, Robot, Node.js and Chromium, your `QMPASS_TOKEN` / `QMPASS_URL`, that
21
+ Qmpass can be reached, and that the token is accepted — without starting a session, so it's safe to
22
+ run while an agent is already running.
23
+
24
+ Optional add-ons, only needed if your tests use them:
25
+
26
+ | Add-on | Install | For tests that |
27
+ |---|---|---|
28
+ | `postgres` | `pipx install "qmpass-test-agent[postgres]"` | query a PostgreSQL database |
29
+ | `mysql` | `pipx install "qmpass-test-agent[mysql]"` | query a MySQL / MariaDB database |
30
+ | `salesforce` | `pipx install "qmpass-test-agent[salesforce]"` | work with Salesforce (large install) |
31
+
32
+ No pipx yet? `brew install pipx` (macOS), `python3 -m pip install --user pipx` (Windows / Linux),
33
+ then `pipx ensurepath`.
34
+
35
+ ## Run
36
+
37
+ Copy the command shown with your agent token in Qmpass, or:
38
+
39
+ ```bash
40
+ export QMPASS_TOKEN=qmp_agent_…
41
+ qmpass-agent run
42
+ ```
43
+
44
+ The agent connects to `https://api.qmpass.ai` (set `QMPASS_URL` for other deployments), waits for
45
+ jobs, and logs one line when each run starts and finishes.
46
+
47
+ Useful options: `--worker N` (parallel jobs, up to 5), `--log-file PATH`, `--log-format json`,
48
+ `--log-level DEBUG`. Run `qmpass-agent --help` for all commands.
49
+
50
+ ## Update
51
+
52
+ ```bash
53
+ pipx upgrade qmpass-test-agent
54
+ ```
55
+
56
+ When a newer version is available, `qmpass-agent run` says so in one line at startup (and `doctor`
57
+ shows it). The agent never updates itself. Set `QMPASS_AGENT_UPDATE_CHECK=0` to turn the check off.
58
+
59
+ ## Exit codes
60
+
61
+ | Code | Meaning |
62
+ |------|---------|
63
+ | 0 | Stopped normally |
64
+ | 2 | Configuration error |
65
+ | 3 | Refused by the platform (invalid or expired token, agent disabled) — the log says which |
66
+ | 4 | Agent too old — run `pipx upgrade qmpass-test-agent` |
67
+ | 5 | A prerequisite is missing (e.g. Node.js) — run `qmpass-agent setup` |
68
+
69
+ ## License
70
+
71
+ Proprietary — for use with a Qmpass subscription. See `LICENSE`.