Files
matrix-docker-ansible-deploy/roles/custom/matrix-bot-baibot/molecule/default/molecule.yml
T
Slavi PantaleevandClaude Opus 5 6bdcddb79a Add a Molecule scenario for baibot, and teach the stub to answer a syncing client
baibot is the first bot rather than a bridge, and the shape
differs from the appservices: it is a plain Matrix client that logs in with a
password, sets up its profile and then syncs. It publishes no port, so nothing
can be probed over HTTP; what it says about itself in the journal is the only
window into whether the role's configuration reached the process.

What the scenario proves:

- The unit is active with no automatic restarts, AND baibot got past startup
  into its sync loop. The second half is what carries the scenario. baibot never
  exits when startup goes wrong - it retries the failing step forever with a
  growing delay - so the unit sits there `active` with `NRestarts` at 0 while
  the bot is permanently half-started. Pointing `user.avatar` at a file that is
  not there reproduces exactly that: the unit assertion still passes, the sync
  assertion does not.
- The display name the bot announces it wants is the role's `user.name`, which
  is neither the role's default nor what the stub reports the account already
  has.
- The rendered `logging` string took effect per target: baibot's own records
  appear at DEBUG (the role ships `info`) while everything underneath stays at
  the `warn` catch-all. The second half is the control, and raising the
  catch-all turns 2 DEBUG records into 161.
- The rendered config carries the scenario's homeserver, identity, command
  prefix, admin patterns and user patterns, and uses password authentication
  exclusively, with the access-token keys rendered as nulls.
- The statically-defined agent survived the provider templating - the
  per-provider template rendered to YAML, parsed, merged and nested into the
  list - key by key.
- The container runs as the uid/gid the playbook supplies (1234, not the 1000
  the base image already has), on the image version defaults/main.yml pins, and
  could write its session into the data path.

No AI provider is contacted and none is needed. baibot calls a provider only
when a message asks an agent to do something, so a static agent with a
placeholder key and a base URL that resolves nowhere still has to survive the
bot's startup parsing - which is the part worth testing.

The shared stub grew what a syncing Matrix client needs and an appservice did
not: /sync (with a `next_batch`, and holding the call open for the timeout the
client asked for, or the bot spins the stub in a hot loop), the media config
and upload endpoints a bot setting its own avatar insists on, /keys/upload with
its key counts, and filter creation. Without the media config in particular,
baibot never gets past profile setup.

The shared stub task gained a STUB_VERBOSE knob. The stub already advertised
the environment variable but there was no way to set it from a scenario, and
for a component with no port of its own its request log is the only place to
see what the component is actually asking for.

Note: molecule-shared/homeserver-stub.py also carries a loosened /login match
from another scenario being written in this same tree at the same time; it was
already in the working copy and is not mine.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SEH3vxYSQ5SV4N5z61eyGT
2026-08-27 18:02:53 +03:00

94 lines
4.2 KiB
YAML

# SPDX-FileCopyrightText: 2026 Slavi Pantaleev
#
# SPDX-License-Identifier: AGPL-3.0-or-later
---
dependency:
name: galaxy
options:
requirements-file: requirements.yml
force: true
driver:
name: docker
platforms:
- name: matrix-bot-baibot-${MOLECULE_DISTRO:-ubuntu2604}-default
image: "geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu2604}-ansible:latest"
command: ${MOLECULE_DOCKER_COMMAND:-""}
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
cgroupns_mode: host
privileged: true
pre_build_image: true
provisioner:
name: ansible
config_options:
defaults:
callback_result_format: yaml
inventory:
group_vars:
all:
matrix_bot_baibot_container_network: matrix-bot-baibot-molecule
# verify.yml runs as its own play, where the role's defaults are out
# of scope, so the paths it reads are pinned here as literals. They
# match what the role derives from matrix_base_data_path.
matrix_bot_baibot_base_path: /matrix/baibot
matrix_bot_baibot_config_path: /matrix/baibot/config
matrix_bot_baibot_data_path: /matrix/baibot/data
# baibot is a plain Matrix client, not an appservice: it logs in with a
# password and then syncs, so a homeserver has to answer for it to get
# anywhere. prepare.yml stands up the shared stub for that.
matrix_bot_baibot_config_homeserver_url: http://matrix.molecule.local:8008
# Deliberately different from the role's defaults (localpart `baibot`,
# name `baibot`, prefix `!bai`, self-introduction on) AND from baibot's
# own built-in defaults, so that a passing assertion cannot be explained
# by "it would have happened anyway".
matrix_bot_baibot_config_user_mxid_localpart: molecule-baibot
matrix_bot_baibot_config_user_name: Molecule baibot
matrix_bot_baibot_config_user_password: molecule_baibot_password_5b7c14
matrix_bot_baibot_config_command_prefix: "!molecule-bai"
matrix_bot_baibot_config_room_post_join_self_introduction_enabled: false
matrix_bot_baibot_config_access_admin_patterns:
- "@molecule-admin:molecule.local"
# `debug` rather than the role's `info`, so the journal carries what the
# bot loaded. verify.yml reads it.
matrix_bot_baibot_config_logging_level_baibot: debug
# baibot talks to AI providers, and a scenario must not need a provider
# account. It does not have to: providers are contacted only when a
# message asks an agent to do something, never at startup. So a static
# agent is defined with a placeholder key and a base URL that resolves
# nowhere. Nothing is ever called, and the agent still has to survive
# baibot's startup parsing of `agents.static_definitions` - which is
# what proves the role's provider templating produced something the bot
# accepts.
matrix_bot_baibot_config_agents_static_definitions_anthropic_enabled: true
matrix_bot_baibot_config_agents_static_definitions_anthropic_id: molecule-anthropic
matrix_bot_baibot_config_agents_static_definitions_anthropic_config_base_url: http://molecule-no-such-provider.invalid/v1
matrix_bot_baibot_config_agents_static_definitions_anthropic_config_api_key: molecule-placeholder-not-a-real-key
matrix_bot_baibot_config_agents_static_definitions_anthropic_config_text_generation_model_id: molecule-model-4-2
matrix_bot_baibot_config_agents_static_definitions_anthropic_config_text_generation_temperature: 0.25
matrix_bot_baibot_config_agents_static_definitions_anthropic_config_text_generation_max_response_tokens: 1234
matrix_bot_baibot_config_agents_static_definitions_anthropic_config_text_generation_max_context_tokens: 56789
env:
# Workaround for https://github.com/ansible/molecule/issues/4391
ANSIBLE_ROLES_PATH: ${MOLECULE_PROJECT_DIRECTORY}/../..:/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:~/.ansible/roles
scenario:
test_sequence:
- dependency
- cleanup
- destroy
- syntax
- create
- prepare
- converge
- idempotence
- verify
- cleanup
- destroy
verifier:
name: ansible