bud_runner is the command-line execution agent for Bud TMP. It runs trusted
Python test suites, emits CI-friendly reports, uploads results to Bud, and can
operate as a long-lived registered runner daemon.
Creator: Amine El Omari
bud_runner is designed for machines you manage, including dedicated lab hosts
and self-hosted CI runners.
- Runs test case lists from local automation or CI.
- Produces JUnit XML, JSON, or text output.
- Creates and updates Bud test runs.
- Uploads test results and artifacts to Bud.
- Runs work the backend has queued for a test station.
- Registers persistent runner identities.
- Runs a heartbeat and local control daemon.
- Spools failed result uploads for later retry.
bud_runner |
Intended budtestlibrary pairing |
Notes |
|---|---|---|
1.0.3 |
1.0.3 |
Backend-queued runs, --artifact uploads, optional addr on FlashEvent |
1.0.2 |
1.0.2 |
Multipart artifact uploads and formatting fixes |
1.0.1 |
1.0.1 |
Timeout fixes and PyPI release structure |
python -m pip install bud-runner budtestlibraryRequirements:
- Python 3.9 or later;
budtestlibrary;- a Bud backend for registration, test-run creation, or result upload.
The package can execute tests and generate local reports without Bloom. Bloom is
not a direct dependency of bud_runner.
bud_runner imports and executes Python test code from the selected local
workspace. Only run test modules you trust. Test code can access files, the
network, subprocesses, and any credentials available to the runner account.
Each discovered test class runs in a separate spawned operating-system process. Per-test and global suite timeouts limit hangs, but process isolation is not a security sandbox.
The daemon control socket binds to 127.0.0.1 by default. Do not expose it to an
untrusted network. Non-loopback binding requires an external protection layer.
python -m bud_runner run-tests \
--test-case-list <Module.ClassName> \
--output report_junit.xml \
--no-uploadpython -m bud_runner run-tests \
--test-case-list <Module.ClassName> \
--backend-url "https://<your-bud-instance-url>" \
--username "ci-user@example.com" \
--password "<bud-password>" \
--uploadIf an upload returns 401 Unauthorized and credentials were supplied,
bud_runner logs in again through the Bud authentication API, refreshes the
cached user token, and retries once.
--artifact (-A) takes a file path or glob and is repeatable. Matching files
are uploaded alongside the results, so logs, captures, and reports stay attached
to the run:
python -m bud_runner run-tests \
--test-case-list <Module.ClassName> \
--artifact "logs/*.log" \
--artifact capture.png \
--uploadA file that fails to upload is reported but does not fail the run.
claim-run asks the backend for this station's next queued run and executes it
through the same path as any other run. With --interval 0 (the default) it
claims once and exits, which suits a cron entry or a one-shot CI job; a non-zero
interval polls continuously:
python -m bud_runner claim-run \
--backend-url "https://<your-bud-instance-url>" \
--username "station-01@example.com" \
--workspace ./tests \
--interval 30 \
--artifact "logs/*.log"--workspace points at the directory holding this station's test modules and
defaults to the current directory. --test-timeout and --suite-timeout cap a
single test and the full suite, at 300 and 1800 seconds respectively.
python -m bud_runner add-test-run \
--test-case-list <Module.ClassName> \
--test-suite-name "Nightly Automated Tests" \
--url-test-software https://github.com/org/tests.git \
--ref-test-software main \
--sw-under-test https://github.com/org/product.git \
--ref-sw-under-test release-2026.07export RUNNER_API_KEY="<registration-secret>"
export BUD_BACKEND_URL="https://<your-bud-instance-url>"
python -m bud_runner register \
--username "lab-station-01" \
--socket-port 53035Runner identity, tokens, and daemon state are stored under ~/.bud/. Keep that
directory private to the runner account and never commit it.
python -m bud_runner daemon \
--username "lab-station-01" \
--location "Hardware Lab" \
--bind-host 127.0.0.1Run the daemon under a service manager such as systemd, launchd, or a Windows service wrapper.
Environment variables:
export BUD_BACKEND_URL="https://<your-bud-instance-url>"
export BUD_TOKEN="<user-token>"
export BUD_RUNNER_ACCOUNT="lab-station-01"
export BUD_RUNNER_TOKEN="<runner-token>"
export RUNNER_API_KEY="<registration-secret>"Project-level, non-secret context can be stored in app.properties:
budBackend=https://<your-bud-instance-url>
budRunnerAccount=lab-station-01Do not put passwords, user tokens, runner tokens, or registration secrets in
app.properties.
| Command | Purpose |
|---|---|
run-tests |
Execute tests, generate reports, and optionally upload results |
claim-run |
Run work the backend has queued for this test station |
list-tests |
Resolve and list discovered tests without executing them |
add-test-run |
Create a Bud test run |
register |
Register or re-register a runner identity |
daemon |
Run heartbeat and local control services |
status |
Show local configuration, versions, and Bud health |
version |
Print the installed package version |
Run python -m bud_runner <command> --help for complete options.
name: Run tests
on:
push:
branches: [main]
jobs:
test:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: python -m pip install bud-runner budtestlibrary
- name: Execute tests
env:
BUD_BACKEND_URL: ${{ secrets.BUD_BACKEND_URL }}
BUD_TOKEN: ${{ secrets.BUD_TOKEN }}
run: |
python -m bud_runner run-tests \
--test-case-list <Module.ClassName> \
--ref-test-software ${{ github.sha }} \
--output report_junit.xml
- uses: actions/upload-artifact@v4
if: always()
with:
name: test-results
path: report_junit.xmlbud_runner is permanent free and open-source software licensed under the
GNU Affero General Public License v3.0 only (AGPL-3.0-only).
No paid EmbedLabs licence is required to use bud_runner, including for
commercial use, provided the AGPL terms are followed. Accepted community
contributions remain publicly available under AGPL-3.0-only and will not
become proprietary-only.
Bud and Bloom are separate source-available applications. Commercial licensing,
deployment, integration, and support offered through sales@embedlabs.de
applies to those applications and services—not to the bud_runner package
licence.
Technical, security, and contribution questions: dev@embedlabs.net.
Copyright (C) 2026 Mohamed Amine El Omari Alaoui, operating under the name EmbedLabs.