Skip to content

Formatting fixes - #412

Merged
azarouski merged 123 commits into
developfrom
formatting-fixes
Oct 14, 2026
Merged

azarouski merged 123 commits into
developfrom
formatting-fixes

Conversation

@azarouski

Copy link
Copy Markdown
Contributor

No description provided.

@azarouski azarouski self-assigned this Aug 16, 2026
azarouski and others added 25 commits August 17, 2026 01:53
Device containers in the devices and mac-devices roles now receive
STORAGE_TOKEN, so screenshot uploads and app-install blob fetches pass the
authenticated STF storage routes. The token is read from the environment to
keep the value out of this tracked repository, and it must match
STORAGE_TOKEN in the STF server variables.env.

DEVICE_VERSION moves to 3.0-hardening-2026.08 so providers run the
security-remediated device image that expects the token.
Updates the provider image reference and adds the new default values
needed by the updated STF image.
Honour the 'wireless' field that has existed in mcloud-devices.txt since
it was introduced but was never read (fields 2-10, 12 and 13 are read;
11 is skipped).

Motivation
----------
Apple TV 4K has no diagnostic port. 'ios listen' therefore never emits a
connect event for it, so create_containers() is never called and the
device cannot join the farm. The device is reachable over Apple's
RemoteXPC tunnel, but that tunnel needs uid 0 and a tun interface on the
host, so it lives outside the container set.

Everything else in the stack already works for such a device, because the
pieces that matter are HTTP and env driven:

  * the appium image builds appium:webDriverAgentUrl as
    http://${WDA_HOST}:${WDA_PORT} (files/zbr-default-caps-gen.sh)
  * the device image registers with STF as --serial ${DEVICE_UDID} from
    env, and health-checks WDA over HTTP
  * appium-xcuitest-driver explicitly supports running off macOS when
    given webDriverAgentUrl (assertWdaHostSessionCapsSupported)

So the only thing that genuinely differs is where WebDriverAgent lives.

Change
------
For rows with wireless=true:
  * skip the connector container -- it exists only to share usbmuxd
  * omit the --link to it from the device and appium containers
  * set WDA_HOST / WDA_PORT from two new device-list fields (14, 15)
  * pass WIRELESS=true to the device and appium containers, consumed by
    zebrunner/mcloud-device#210 and zebrunner/appium#439

Rows without wireless=true are untouched: same --link, same
WDA_HOST=connector, same connector container. Verified by simulation that
the docker arguments generated for a usb row are byte-identical.
WDA_PORT is now passed explicitly on the usb path too; both images
already default it to 8100, so that is a no-op.

Fails fast with an explicit message if wireless=true but no wda_host is
given, rather than starting containers that cannot work.

Notes
-----
Empty-array expansion uses ${arr[@]+"${arr[@]}"} because macOS ships
bash 3.2, where "${arr[@]}" on an empty array is an unbound-variable
error under 'set -u'.

No change is needed in listen()/on-usb-update: 'start <udid>' already
exists as a CLI verb, so an external owner of the tunnel can start and
stop these devices directly.

Verified end to end on an Apple TV 4K (AppleTV14,1) on tvOS 18.4 and
26.6: a Linux container with no Xcode, no macOS and no tunnel access
created an Appium session and drove the device (page source, screenshot,
button press, active app).
Support wireless (portless) iOS/tvOS devices by honouring the existing 'wireless' field
values for "wireless" were changed to lowercase
Change the way sudo permissions provided for ansible
azarouski and others added 28 commits October 6, 2026 23:57
- tests/zebrunner_test.sh runs zebrunner.sh on a copy of the repo with a
  temporary HOME and stubbed sudo/launchctl/docker/ansible-playbook/uname:
  help, setup, version, ansible arguments, status, backup/restore and the
  Linux and macOS shutdown (sudo only records its calls)
- tests/utility_test.sh: confirm, random_string, delimiter, replace and the
  message helpers

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- lint job plus a test job on ubuntu-latest and macos-latest running
  tests/run_all.sh (listener and usbmuxd_watch tests need macOS)
- tests/Dockerfile: Linux test environment to run the Linux tests on macOS
- README: how to run the tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
actions/checkout@v4 and actions/setup-python@v5 target the deprecated
Node.js 20; v7 of both run on Node.js 24 and do not change the inputs used.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pushes to and pull requests into develop, main and master (the current
default branch) trigger the tests; other branches are tested through their
pull requests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- workflow_dispatch to run the tests on any branch manually
- a new push to a pull request cancels its outdated run; runs of
  develop/main/master are never cancelled
- the GITHUB_TOKEN only reads the repository contents
- job timeouts stop hung runs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only ids and names were checked, so a missing obligatory field, a wrong os or
port range, or a host port shared by devices passed the deploy and broke the
containers start later. The prechecks validate obligatory fields and port
ranges, that the published host ports (appium_port and the min_port-max_port
range) are not shared, and on macOS that a wireless device has wda_host.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
logs/listener.log grew without limit. newsyslog cannot truncate in place, and
a file kept open by launchd (StandardOutPath) would keep being written after
the rotation, so the listener appends its messages and every zebrunner-farm
action output to the log per write now. The deploy installs a newsyslog rule
(10 MB, 7 bzip2 archives, no signal) into /etc/newsyslog.d, shutdown removes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
README suggested --extra-vars "ansible_sudo_pass=PSWD", which leaves the
password in the shell history and the processes list. The examples rely on the
interactive --ask-become-pass now, and the non-interactive run keeps the
password in an ansible-vault encrypted become.yml (ignored by git).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`tr < /dev/urandom | head` never ended when SIGPIPE is ignored, as for the
processes of CI runners, so `zebrunner.sh backup` hung on the macOS runner;
and LC_CTYPE=C did not override a UTF-8 LC_ALL, so tr failed with "Illegal
byte sequence" and returned an empty string. random_string reads finite
chunks of /dev/urandom with LC_ALL=C now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The roles use ansible_facts['system'] only, while the full facts gathering
runs system_profiler on macOS, which took about 70 seconds per playbook on
the GitHub macOS runner and made the ansible tests run for 23 minutes. The
test plays use the same setting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI, the tests Docker image and local runs install the same versions of the
linters (shellcheck too: the runner had 0.9.0, newer versions are stricter).
tests/lint.sh reports missing tools with the install command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
.yamllint extends the default rules with 160 chars lines, true/false only
booleans and the *.yml.original settings examples; local settings ignored by
git are skipped. The findings were fixed: yes/no booleans, comments without
a space after #, too long comments and the workflow document start.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ruff.toml: 120 chars lines, pycodestyle, pyflakes, imports order, bugbear,
pyupgrade and simplify rules. tests/fake_usbmuxd.py was formatted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DL3008 (pinned apt versions) is ignored: package versions of ubuntu:24.04
change with the security updates. ruff runs without its cache, so the
linters work on a read-only checkout (e.g. mounted into the tests image).
The hadolint-py wheel for macOS is broken, README suggests brew or docker.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
.pymarkdown disables the line length rule and allows the HTML of the
centered logo and the requirements table. README formatting was fixed:
consistent headings, blank lines around headings, lists and code blocks,
code block languages and list indentation. A bare http://<PUBLIC_IP>/stf
was rendered by GitHub as http:///stf, it is quoted as code now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The roles pass the production profile now: modules by their full names,
named plays, Jinja spacing, the role variables prefixed by the role name,
docker pull by command, launchctl calls as argv lists (too long lines) and
the two intended ignore_errors with a reason. ansible-lint formatted the
YAML (double quotes, no blank line after ---), .yamllint got the settings it
requires. Skipped: var-naming[pattern] and role-name, as the existing farms
set the upper case variables in roles/mac-devices/vars/main.yml.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
.editorconfig keeps the style for shfmt and editors: 2 spaces indents and
a space after redirections, the closest to the existing code. The scripts
and the zebrunner-farm/listener templates were formatted; the Jinja
expressions of the templates did not change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The macOS runner still spent about 70 seconds per playbook with the minimal
facts (c985f33 did not help: the hardware facts were not the cause, a slow
hostname lookup by socket.getfqdn() is suspected), so the ansible tests hit
the 20 minutes job timeout. The facts are gathered by the first playbook and
taken from a jsonfile cache by the others.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A diagnostic step before the tests times socket.gethostname(),
socket.getfqdn() and the minimal Ansible facts, to find out what takes
about 70 seconds per playbook on the macOS runner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tests/diagnose_facts.sh prints the host names and DNS settings and times
the hostname lookups, the commands and Python calls of the minimal facts,
every minimal facts collector alone, the Python interpreter discovery and
playbooks with and without facts. The CI step may fail or time out (12 min)
without failing the tests. Both are to be removed once the cause is known.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CI diagnostics showed that on the GitHub macOS runner every reverse
lookup and the lookup of the own host name time out after 35 seconds, so
socket.getfqdn() of the Ansible platform facts takes 70 seconds; the other
collectors, the interpreter discovery and ansible-playbook itself are fast.
The ansible tests keep gathering the facts once and caching them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Makefile installs the linters of tests/requirements-lint.txt into .venv
(again when the requirements change; on macOS hadolint comes from brew, the
hadolint-py wheel is broken), then runs tests/lint.sh and tests/run_all.sh
on this machine and in the Linux docker image. make lint, make test and
make docker run a part of the checks; make lists the targets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With JUNIT_DIR set, every check is written into ${JUNIT_DIR}/<test>.xml:
the section in the test case name, the expected and actual values of a
failure, skipped tests and checks, and an exit before finishing as a
failure; the text is XML escaped, control characters are dropped.
tests/lint.sh runs every linter as a check and reports all failures
instead of stopping at the first one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The lint and tests jobs write JUnit XML and publish it, also when a check
failed: mikepenz/action-junit-report (pinned by SHA) adds annotations and a
detailed job summary without a check run, so the read-only token is enough
also for pull requests from forks; upload-artifact keeps the XML files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- macOS 13+ on Apple Silicon and Intel (universal usbmuxd_watch)
- official docker and ansible install docs, ansible 2.10+ (ansible.builtin
  module names), go-ios purpose
- the devices settings validation of the deploy
- the macOS devices listener (USB devices only) and its log rotation
- WebDriverAgent has to be installed in advance on macOS: the connector
  installs it on Linux only
- zebrunner.sh commands; udev and syslog troubleshooting marked as Linux

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@azarouski
azarouski merged commit 8ffa40f into develop Oct 14, 2026
@azarouski
azarouski deleted the formatting-fixes branch October 14, 2026 19:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants