Matrix Docker Ansible eploy
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

505 строки
27 KiB

  1. # SPDX-FileCopyrightText: 2026 Slavi Pantaleev
  2. #
  3. # SPDX-License-Identifier: AGPL-3.0-or-later
  4. ---
  5. # Meowlnir's authenticated management API and Postgres schema are the readiness evidence.
  6. # The homeserver is a deliberately limited local stub, so no claim is made about moderation.
  7. - name: Verify matrix-bot-meowlnir
  8. hosts: all
  9. become: true
  10. vars_files:
  11. - "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/../../../molecule-shared/vars.yml"
  12. - "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/../../../molecule-shared/playbook-context.yml"
  13. vars:
  14. matrix_bot_meowlnir_rendered_config: "{{ matrix_bot_meowlnir_config_file.content | b64decode | from_yaml }}"
  15. matrix_bot_meowlnir_rendered_registration: "{{ matrix_bot_meowlnir_registration_file.content | b64decode | from_yaml }}"
  16. matrix_bot_meowlnir_api_body: "{{ matrix_bot_meowlnir_api_http.stdout_lines[:-1] | join('\n') }}"
  17. matrix_bot_meowlnir_api_response: "{{ matrix_bot_meowlnir_api_body | from_json }}"
  18. matrix_bot_meowlnir_expected_database_uri: >-
  19. postgresql://{{ matrix_bot_meowlnir_database_username }}:{{ matrix_bot_meowlnir_database_password }}@{{ matrix_bot_meowlnir_database_hostname }}:5432/{{ matrix_bot_meowlnir_database_name }}?sslmode={{ matrix_bot_meowlnir_database_sslmode }}
  20. matrix_bot_meowlnir_labels_lines: "{{ (matrix_bot_meowlnir_labels_file.content | b64decode).splitlines() }}"
  21. matrix_bot_meowlnir_runtime: "{{ (matrix_bot_meowlnir_container_inspect.stdout | from_json) | first }}"
  22. matrix_bot_meowlnir_config_mounts: "{{ matrix_bot_meowlnir_runtime.Mounts | selectattr('Destination', 'equalto', '/data/config') | list }}"
  23. matrix_bot_meowlnir_data_mounts: "{{ matrix_bot_meowlnir_runtime.Mounts | selectattr('Destination', 'equalto', '/data') | list }}"
  24. gather_facts: false
  25. tasks:
  26. - name: Load the role's defaults under a separate name
  27. ansible.builtin.include_vars:
  28. file: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/defaults/main.yml"
  29. name: matrix_bot_meowlnir_role_defaults
  30. - name: Wait for the matrix-bot-meowlnir service to become active
  31. ansible.builtin.systemd_service:
  32. name: matrix-bot-meowlnir.service
  33. register: matrix_bot_meowlnir_service
  34. until: matrix_bot_meowlnir_service.status.ActiveState == 'active'
  35. retries: 30
  36. delay: 5
  37. failed_when: false
  38. - name: Assert the service is active and has not restarted
  39. ansible.builtin.assert:
  40. that:
  41. - matrix_bot_meowlnir_service.status.ActiveState == 'active'
  42. - matrix_bot_meowlnir_service.status.NRestarts is defined
  43. - matrix_bot_meowlnir_service.status.NRestarts | int == 0
  44. fail_msg: >-
  45. matrix-bot-meowlnir.service is
  46. {{ matrix_bot_meowlnir_service.status.ActiveState | default('unknown') }} after
  47. {{ matrix_bot_meowlnir_service.status.NRestarts | default('?') }} restart(s)
  48. success_msg: "matrix-bot-meowlnir.service is active and has not restarted"
  49. - name: Wait for Meowlnir's authenticated management API
  50. ansible.builtin.command:
  51. argv:
  52. - docker
  53. - run
  54. - --rm
  55. - --network={{ matrix_bot_meowlnir_container_network }}
  56. - "{{ molecule_shared_image_curl }}"
  57. - --silent
  58. - --show-error
  59. - --header
  60. - 'Authorization: Bearer molecule_management_secret_a64528'
  61. - --write-out
  62. - "\nHTTP_STATUS=%{http_code}"
  63. - http://matrix-bot-meowlnir:29439/_meowlnir/v1/bots
  64. register: matrix_bot_meowlnir_api_http
  65. changed_when: false
  66. until: "'HTTP_STATUS=200' in matrix_bot_meowlnir_api_http.stdout"
  67. retries: 24
  68. delay: 5
  69. failed_when: false
  70. - name: Assert the management API authenticated the configured secret
  71. ansible.builtin.assert:
  72. that:
  73. - matrix_bot_meowlnir_api_http.rc == 0
  74. - matrix_bot_meowlnir_api_http.stdout_lines[-1] == 'HTTP_STATUS=200'
  75. - matrix_bot_meowlnir_api_response is mapping
  76. - matrix_bot_meowlnir_api_response.bots is sequence
  77. - matrix_bot_meowlnir_api_response.bots | length == 0
  78. fail_msg: >-
  79. Meowlnir's management API did not authenticate or return its empty bot roster
  80. ({{ matrix_bot_meowlnir_api_http.stdout | default('no output') }})
  81. success_msg: "Meowlnir's live management API authenticated the configured secret"
  82. - name: Ask the management API with a wrong secret
  83. ansible.builtin.command:
  84. argv:
  85. - docker
  86. - run
  87. - --rm
  88. - --network={{ matrix_bot_meowlnir_container_network }}
  89. - "{{ molecule_shared_image_curl }}"
  90. - --silent
  91. - --show-error
  92. - --header
  93. - 'Authorization: Bearer molecule_wrong_secret'
  94. - --output
  95. - /dev/null
  96. - --write-out
  97. - "HTTP_STATUS=%{http_code}"
  98. - http://matrix-bot-meowlnir:29439/_meowlnir/v1/bots
  99. register: matrix_bot_meowlnir_wrong_secret_http
  100. changed_when: false
  101. failed_when: false
  102. - name: Assert the management API rejects a wrong secret
  103. ansible.builtin.assert:
  104. that:
  105. - matrix_bot_meowlnir_wrong_secret_http.rc == 0
  106. - matrix_bot_meowlnir_wrong_secret_http.stdout in ['HTTP_STATUS=401', 'HTTP_STATUS=403']
  107. fail_msg: "Meowlnir's management API accepted the wrong bearer secret"
  108. success_msg: "Meowlnir's management API rejects a wrong bearer secret"
  109. # This is the appservice half of the live homeserver handshake. A valid empty
  110. # transaction can only reach the dispatcher if the process loaded its hs_token.
  111. - name: Send a homeserver transaction to Meowlnir's appservice API
  112. ansible.builtin.command:
  113. argv:
  114. - docker
  115. - run
  116. - --rm
  117. - --network={{ matrix_bot_meowlnir_container_network }}
  118. - "{{ molecule_shared_image_curl }}"
  119. - --silent
  120. - --show-error
  121. - --request
  122. - PUT
  123. - --header
  124. - 'Authorization: Bearer molecule_hs_token_c20dc3'
  125. - --header
  126. - 'Content-Type: application/json'
  127. - --data
  128. - '{"events":[],"ephemeral":[],"to_device":[]}'
  129. - --write-out
  130. - "\nHTTP_STATUS=%{http_code}"
  131. - http://matrix-bot-meowlnir:29439/_matrix/app/v1/transactions/molecule-transaction
  132. register: matrix_bot_meowlnir_transaction_http
  133. changed_when: false
  134. failed_when: false
  135. - name: Assert Meowlnir accepts a transaction authenticated with the configured homeserver token
  136. ansible.builtin.assert:
  137. that:
  138. - matrix_bot_meowlnir_transaction_http.rc == 0
  139. - matrix_bot_meowlnir_transaction_http.stdout_lines[-1] == 'HTTP_STATUS=200'
  140. - matrix_bot_meowlnir_transaction_http.stdout_lines[:-1] | join('\n') | from_json == {}
  141. fail_msg: >-
  142. Meowlnir rejected an empty appservice transaction carrying the configured hs_token
  143. ({{ matrix_bot_meowlnir_transaction_http.stdout | default('no output') }})
  144. success_msg: "Meowlnir accepts transactions carrying the configured homeserver token"
  145. - name: Send an appservice transaction with a wrong homeserver token
  146. ansible.builtin.command:
  147. argv:
  148. - docker
  149. - run
  150. - --rm
  151. - --network={{ matrix_bot_meowlnir_container_network }}
  152. - "{{ molecule_shared_image_curl }}"
  153. - --silent
  154. - --show-error
  155. - --request
  156. - PUT
  157. - --header
  158. - 'Authorization: Bearer molecule_wrong_hs_token'
  159. - --header
  160. - 'Content-Type: application/json'
  161. - --data
  162. - '{"events":[]}'
  163. - --output
  164. - /dev/null
  165. - --write-out
  166. - "HTTP_STATUS=%{http_code}"
  167. - http://matrix-bot-meowlnir:29439/_matrix/app/v1/transactions/molecule-wrong-token
  168. register: matrix_bot_meowlnir_wrong_transaction_http
  169. changed_when: false
  170. failed_when: false
  171. - name: Assert Meowlnir rejects a transaction with the wrong homeserver token
  172. ansible.builtin.assert:
  173. that:
  174. - matrix_bot_meowlnir_wrong_transaction_http.rc == 0
  175. - matrix_bot_meowlnir_wrong_transaction_http.stdout == 'HTTP_STATUS=401'
  176. fail_msg: "Meowlnir accepted an appservice transaction carrying a wrong hs_token"
  177. success_msg: "Meowlnir rejects transactions carrying a wrong homeserver token"
  178. - name: Probe the role's default Meowlnir port
  179. ansible.builtin.command:
  180. argv:
  181. - docker
  182. - run
  183. - --rm
  184. - --network={{ matrix_bot_meowlnir_container_network }}
  185. - "{{ molecule_shared_image_curl }}"
  186. - --silent
  187. - --show-error
  188. - --max-time
  189. - '3'
  190. - --output
  191. - /dev/null
  192. - --write-out
  193. - "HTTP_STATUS=%{http_code}"
  194. - http://matrix-bot-meowlnir:29339/_meowlnir/v1/bots
  195. register: matrix_bot_meowlnir_default_port_http
  196. changed_when: false
  197. failed_when: false
  198. - name: Assert Meowlnir is not listening on the role's default port
  199. ansible.builtin.assert:
  200. that:
  201. - matrix_bot_meowlnir_default_port_http.rc != 0
  202. - matrix_bot_meowlnir_default_port_http.stdout == 'HTTP_STATUS=000'
  203. fail_msg: "Meowlnir still answers on 29339, so the configured port is not proven"
  204. success_msg: "Meowlnir does not listen on the role's default port"
  205. - name: Read the configuration file the role rendered
  206. ansible.builtin.slurp:
  207. src: "{{ matrix_bot_meowlnir_config_path }}/config.yaml"
  208. register: matrix_bot_meowlnir_config_file
  209. - name: Assert the parsed homeserver and appservice configuration
  210. ansible.builtin.assert:
  211. that:
  212. - matrix_bot_meowlnir_rendered_config.homeserver.address == matrix_bot_meowlnir_config_homeserver_address
  213. - matrix_bot_meowlnir_rendered_config.homeserver.domain == matrix_bot_meowlnir_config_homeserver_domain
  214. - matrix_bot_meowlnir_rendered_config.meowlnir.id == matrix_bot_meowlnir_appservice_id
  215. - matrix_bot_meowlnir_rendered_config.meowlnir.as_token == matrix_bot_meowlnir_appservice_token
  216. - matrix_bot_meowlnir_rendered_config.meowlnir.hs_token == matrix_bot_meowlnir_homeserver_token
  217. - matrix_bot_meowlnir_rendered_config.meowlnir.address == matrix_bot_meowlnir_appservice_url
  218. - matrix_bot_meowlnir_rendered_config.meowlnir.hostname == '0.0.0.0'
  219. - matrix_bot_meowlnir_rendered_config.meowlnir.port == matrix_bot_meowlnir_config_meowlnir_port
  220. fail_msg: "The parsed configuration lost the scenario's Matrix/appservice wiring"
  221. success_msg: "The parsed configuration carries the scenario's Matrix/appservice wiring"
  222. - name: Assert the parsed Meowlnir behavior and secrets
  223. ansible.builtin.assert:
  224. that:
  225. - matrix_bot_meowlnir_rendered_config.meowlnir.management_secret == matrix_bot_meowlnir_config_meowlnir_management_secret
  226. - matrix_bot_meowlnir_rendered_config.meowlnir.data_secret == matrix_bot_meowlnir_config_meowlnir_data_secret
  227. - matrix_bot_meowlnir_rendered_config.meowlnir.federation_auth is sameas true
  228. - matrix_bot_meowlnir_rendered_config.meowlnir.dry_run is sameas true
  229. - matrix_bot_meowlnir_rendered_config.meowlnir.untrusted is sameas true
  230. - matrix_bot_meowlnir_rendered_config.meowlnir.report_room == '!molecule-reports:molecule.local'
  231. - matrix_bot_meowlnir_rendered_config.meowlnir.room_ban_room == '!molecule-bans:molecule.local'
  232. - matrix_bot_meowlnir_rendered_config.meowlnir.hacky_rule_filter == ['@trusted:molecule.local', 'trusted.invalid']
  233. - matrix_bot_meowlnir_rendered_config.meowlnir.hacky_redact_patterns == ['spam', 'molecule-abuse-*']
  234. - matrix_bot_meowlnir_rendered_config.meowlnir.admin_tokens['@molecule-admin:molecule.local'] == 'molecule_admin_token_7e6ce0'
  235. fail_msg: "The parsed configuration lost the non-default Meowlnir behavior"
  236. success_msg: "The parsed configuration carries the non-default Meowlnir behavior"
  237. - name: Assert the parsed provisioning, antispam and policy configuration
  238. ansible.builtin.assert:
  239. that:
  240. - matrix_bot_meowlnir_rendered_config.meowlnir4all.admin_room == '!molecule-provisioning:molecule.local'
  241. - matrix_bot_meowlnir_rendered_config.meowlnir4all.localpart_template == matrix_bot_meowlnir_user_prefix + ('{' + '{ uuidgen }' + '}')
  242. - matrix_bot_meowlnir_rendered_config.meowlnir4all.displayname == 'Molecule Provisioned Meowlnir'
  243. - matrix_bot_meowlnir_rendered_config.meowlnir4all.avatar_url == 'mxc://molecule.local/meowlnir-avatar'
  244. - matrix_bot_meowlnir_rendered_config.meowlnir4all.room_name == 'Molecule Meowlnir Control'
  245. - matrix_bot_meowlnir_rendered_config.meowlnir4all.default_watched_lists | length == 1
  246. - matrix_bot_meowlnir_rendered_config.meowlnir4all.default_watched_lists[0].name == 'Molecule policy list'
  247. - matrix_bot_meowlnir_rendered_config.meowlnir4all.default_watched_lists[0].room_id == '!molecule-policy:molecule.local'
  248. - matrix_bot_meowlnir_rendered_config.meowlnir4all.default_watched_lists[0].shortcode == 'molecule'
  249. - matrix_bot_meowlnir_rendered_config.meowlnir4all.default_watched_lists[0].auto_unban is sameas false
  250. - matrix_bot_meowlnir_rendered_config.antispam.secret == matrix_bot_meowlnir_config_antispam_secret
  251. - matrix_bot_meowlnir_rendered_config.antispam.filter_local_invites is sameas true
  252. - matrix_bot_meowlnir_rendered_config.antispam.auto_reject_invites_token == 'molecule_reject_token_a9812f'
  253. - matrix_bot_meowlnir_rendered_config.antispam.notify_management_room is sameas true
  254. - matrix_bot_meowlnir_rendered_config.antispam.block_invites_to == ['@blocked:molecule.local']
  255. - matrix_bot_meowlnir_rendered_config.policy_server.always_redact is sameas false
  256. - matrix_bot_meowlnir_rendered_config.policy_server.signing_key.startswith('ed25519 policy_server ')
  257. fail_msg: "The parsed provisioning/antispam/policy blocks lost scenario values"
  258. success_msg: "The parsed provisioning/antispam/policy blocks carry scenario values"
  259. - name: Assert the parsed Postgres and logging configuration
  260. ansible.builtin.assert:
  261. that:
  262. - matrix_bot_meowlnir_rendered_config.database.type == 'postgres'
  263. - matrix_bot_meowlnir_rendered_config.database.uri == matrix_bot_meowlnir_expected_database_uri
  264. - matrix_bot_meowlnir_rendered_config.database.max_open_conns == 13
  265. - matrix_bot_meowlnir_rendered_config.database.max_idle_conns == 3
  266. - matrix_bot_meowlnir_rendered_config.database.max_conn_idle_time == '47s'
  267. - matrix_bot_meowlnir_rendered_config.database.max_conn_lifetime == '11m'
  268. - matrix_bot_meowlnir_rendered_config.synapse_db.type == 'postgres'
  269. - matrix_bot_meowlnir_rendered_config.synapse_db.uri == ''
  270. - matrix_bot_meowlnir_rendered_config.logging.min_level == 'debug'
  271. - "matrix_bot_meowlnir_rendered_config.logging.writers == [{'type': 'stdout', 'format': 'json'}]"
  272. fail_msg: "The parsed database/logging blocks lost scenario values"
  273. success_msg: "The parsed database/logging blocks carry scenario values"
  274. - name: Read the appservice registration the role rendered
  275. ansible.builtin.slurp:
  276. src: "{{ matrix_bot_meowlnir_config_path }}/registration.yaml"
  277. register: matrix_bot_meowlnir_registration_file
  278. - name: Assert the parsed appservice registration contract
  279. ansible.builtin.assert:
  280. that:
  281. - matrix_bot_meowlnir_rendered_registration.id == matrix_bot_meowlnir_appservice_id
  282. - matrix_bot_meowlnir_rendered_registration.as_token == matrix_bot_meowlnir_appservice_token
  283. - matrix_bot_meowlnir_rendered_registration.hs_token == matrix_bot_meowlnir_homeserver_token
  284. - matrix_bot_meowlnir_rendered_registration.url == matrix_bot_meowlnir_appservice_url
  285. - matrix_bot_meowlnir_rendered_registration.sender_localpart == matrix_bot_meowlnir_appservice_sender_localpart
  286. - matrix_bot_meowlnir_rendered_registration.rate_limited is sameas false
  287. - matrix_bot_meowlnir_rendered_registration.namespaces.users | length == 2
  288. - matrix_bot_meowlnir_rendered_registration.namespaces.users[0].exclusive is sameas true
  289. - matrix_bot_meowlnir_rendered_registration.namespaces.users[0].regex == '^@molecule_meowlnir_bot_[a-zA-Z0-9._=/+-]+:molecule\\.local$'
  290. - matrix_bot_meowlnir_rendered_registration.namespaces.users[1].regex == '^@molecule_meowlnir_as:molecule\\.local$'
  291. - matrix_bot_meowlnir_rendered_registration['de.sorunome.msc2409.push_ephemeral'] is not defined
  292. fail_msg: "The appservice registration lost its tokens, address or namespaces"
  293. success_msg: "The appservice registration carries its tokens, address and namespaces"
  294. - name: List the tables Meowlnir created in Postgres
  295. ansible.builtin.command:
  296. argv:
  297. - docker
  298. - exec
  299. - matrix-postgres-molecule
  300. - psql
  301. - --username={{ matrix_bot_meowlnir_database_username }}
  302. - --dbname={{ matrix_bot_meowlnir_database_name }}
  303. - --tuples-only
  304. - --no-align
  305. - --command=SELECT tablename FROM pg_tables WHERE schemaname = 'public'
  306. register: matrix_bot_meowlnir_tables
  307. changed_when: false
  308. - name: Assert Meowlnir migrated its schema into the configured Postgres database
  309. ansible.builtin.assert:
  310. that:
  311. - matrix_bot_meowlnir_tables.rc == 0
  312. - "'version' in matrix_bot_meowlnir_table_names"
  313. - "'bot' in matrix_bot_meowlnir_table_names"
  314. - "'management_room' in matrix_bot_meowlnir_table_names"
  315. - "'mx_version' in matrix_bot_meowlnir_table_names"
  316. - "'mx_room_state' in matrix_bot_meowlnir_table_names"
  317. - "'policy_server_signature' in matrix_bot_meowlnir_table_names"
  318. - matrix_bot_meowlnir_table_names | length == 10
  319. fail_msg: >-
  320. Meowlnir did not create a substantial schema in {{ matrix_bot_meowlnir_database_name }}
  321. (found {{ matrix_bot_meowlnir_table_names | length }} table(s))
  322. success_msg: "Meowlnir migrated its schema into the configured Postgres database"
  323. vars:
  324. matrix_bot_meowlnir_table_names: "{{ matrix_bot_meowlnir_tables.stdout_lines | select | list }}"
  325. - name: Read Meowlnir's two database migration markers
  326. ansible.builtin.command:
  327. argv:
  328. - docker
  329. - exec
  330. - matrix-postgres-molecule
  331. - psql
  332. - --username={{ matrix_bot_meowlnir_database_username }}
  333. - --dbname={{ matrix_bot_meowlnir_database_name }}
  334. - --tuples-only
  335. - --no-align
  336. - --command=SELECT 'main:' || version || ':' || compat FROM version UNION ALL SELECT 'matrix_state:' || version || ':' || compat FROM mx_version ORDER BY 1
  337. register: matrix_bot_meowlnir_migration_versions
  338. changed_when: false
  339. - name: Assert both Meowlnir schema sections reached their expected versions
  340. ansible.builtin.assert:
  341. that:
  342. - matrix_bot_meowlnir_migration_versions.rc == 0
  343. - matrix_bot_meowlnir_migration_versions.stdout_lines | select | list == ['main:3:1', 'matrix_state:11:3']
  344. fail_msg: >-
  345. Meowlnir's main and Matrix-state migrations did not reach versions 3 and 11
  346. ({{ matrix_bot_meowlnir_migration_versions.stdout_lines | select | list }})
  347. success_msg: "Both Meowlnir database schema sections reached their expected versions"
  348. - name: Read the labels the role rendered
  349. ansible.builtin.slurp:
  350. src: "{{ matrix_bot_meowlnir_base_path }}/labels"
  351. register: matrix_bot_meowlnir_labels_file
  352. - name: Assert the labels carry the configured reporting and policy routes
  353. ansible.builtin.assert:
  354. that:
  355. - "'traefik.enable=true' in matrix_bot_meowlnir_labels_lines"
  356. - "'traefik.docker.network=matrix-bot-meowlnir-molecule' in matrix_bot_meowlnir_labels_lines"
  357. - "'traefik.http.services.matrix-bot-meowlnir.loadbalancer.server.port=29439' in matrix_bot_meowlnir_labels_lines"
  358. - "'traefik.http.routers.matrix-bot-meowlnir-reporting.rule=Host(`reports.molecule.local`) && PathRegexp(`^/molecule-report/(rooms|users)/[^/]+$`)' in matrix_bot_meowlnir_labels_lines"
  359. - "'traefik.http.routers.matrix-bot-meowlnir-reporting.priority=731' in matrix_bot_meowlnir_labels_lines"
  360. - "'traefik.http.routers.matrix-bot-meowlnir-reporting.entrypoints=web' in matrix_bot_meowlnir_labels_lines"
  361. - "'traefik.http.routers.matrix-bot-meowlnir-reporting.tls=false' in matrix_bot_meowlnir_labels_lines"
  362. - "'traefik.http.routers.matrix-bot-meowlnir-policy-server.rule=Host(`federation.molecule.local`) && PathPrefix(`/molecule-policy`)' in matrix_bot_meowlnir_labels_lines"
  363. - "'traefik.http.routers.matrix-bot-meowlnir-policy-server.priority=733' in matrix_bot_meowlnir_labels_lines"
  364. - "'traefik.http.routers.matrix-bot-meowlnir-policy-server.entrypoints=web' in matrix_bot_meowlnir_labels_lines"
  365. - "'traefik.http.routers.matrix-bot-meowlnir-policy-server.tls=false' in matrix_bot_meowlnir_labels_lines"
  366. - "'molecule.meowlnir.coverage=enabled' in matrix_bot_meowlnir_labels_lines"
  367. fail_msg: "The role's labels lost the non-default public routing contract"
  368. success_msg: "The role's labels carry the non-default public routing contract"
  369. - name: Inspect the running Meowlnir container
  370. ansible.builtin.command:
  371. argv:
  372. - docker
  373. - container
  374. - inspect
  375. - matrix-bot-meowlnir
  376. register: matrix_bot_meowlnir_container_inspect
  377. changed_when: false
  378. - name: Assert the running container uses the exact image pinned by the role
  379. ansible.builtin.assert:
  380. that:
  381. - matrix_bot_meowlnir_runtime.Config.Image == matrix_bot_meowlnir_expected_image
  382. fail_msg: "The running Meowlnir container does not use the role's exact image pin"
  383. success_msg: "The running container uses the exact image pinned by the role"
  384. vars:
  385. matrix_bot_meowlnir_expected_image: >-
  386. {{ matrix_bot_meowlnir_role_defaults.matrix_bot_meowlnir_container_image_registry_prefix_upstream_default }}{{ matrix_bot_meowlnir_role_defaults.matrix_bot_meowlnir_container_image_registry_namespace_identifier }}:{{ matrix_bot_meowlnir_role_defaults.matrix_bot_meowlnir_version }}
  387. - name: Assert the running container uses the playbook's matrix identity
  388. ansible.builtin.assert:
  389. that:
  390. - matrix_bot_meowlnir_runtime.Config.User.split(':')[0] == matrix_user_uid | string
  391. - matrix_bot_meowlnir_runtime.Config.User.split(':')[1] == matrix_user_gid | string
  392. fail_msg: >-
  393. Meowlnir runs as {{ matrix_bot_meowlnir_runtime.Config.User }} instead of
  394. {{ matrix_user_uid }}:{{ matrix_user_gid }}
  395. success_msg: "The running container uses the playbook's matrix UID and GID"
  396. - name: Assert the running container has the role's exact command
  397. ansible.builtin.assert:
  398. that:
  399. - matrix_bot_meowlnir_runtime.Config.Cmd == ['/usr/bin/meowlnir', '--config=/data/config/config.yaml', '--no-update']
  400. fail_msg: "The running Meowlnir container command differs from the role contract"
  401. success_msg: "The running container has the role's exact command"
  402. - name: Assert the container root filesystem is read-only
  403. ansible.builtin.assert:
  404. that:
  405. - matrix_bot_meowlnir_runtime.HostConfig.ReadonlyRootfs is sameas true
  406. fail_msg: "The Meowlnir container root filesystem is writable"
  407. success_msg: "The Meowlnir container root filesystem is read-only"
  408. - name: Assert all Linux capabilities are dropped
  409. ansible.builtin.assert:
  410. that:
  411. - matrix_bot_meowlnir_runtime.HostConfig.CapDrop == ['ALL']
  412. fail_msg: "The Meowlnir container does not drop all Linux capabilities"
  413. success_msg: "The Meowlnir container drops all Linux capabilities"
  414. - name: Assert the configuration bind mount is read-only
  415. ansible.builtin.assert:
  416. that:
  417. - matrix_bot_meowlnir_config_mounts | length == 1
  418. - matrix_bot_meowlnir_config_mounts[0].RW is sameas false
  419. - matrix_bot_meowlnir_config_mounts[0].Source == matrix_bot_meowlnir_config_path
  420. fail_msg: "The Meowlnir configuration bind mount is missing, misplaced or writable"
  421. success_msg: "The configuration bind mount is present and read-only"
  422. - name: Assert the data bind mount is writable
  423. ansible.builtin.assert:
  424. that:
  425. - matrix_bot_meowlnir_data_mounts | length == 1
  426. - matrix_bot_meowlnir_data_mounts[0].RW is sameas true
  427. - matrix_bot_meowlnir_data_mounts[0].Source == matrix_bot_meowlnir_data_path
  428. fail_msg: "The Meowlnir data bind mount is missing, misplaced or read-only"
  429. success_msg: "The data bind mount is present and writable"
  430. - name: Assert the container is attached only to its dedicated network
  431. ansible.builtin.assert:
  432. that:
  433. - matrix_bot_meowlnir_runtime.NetworkSettings.Networks is mapping
  434. - matrix_bot_meowlnir_runtime.NetworkSettings.Networks | length == 1
  435. - matrix_bot_meowlnir_container_network in matrix_bot_meowlnir_runtime.NetworkSettings.Networks
  436. fail_msg: >-
  437. Meowlnir has unexpected networks:
  438. {{ matrix_bot_meowlnir_runtime.NetworkSettings.Networks.keys() | list }}
  439. success_msg: "The container is attached only to its dedicated network"
  440. - name: Ask Docker for Meowlnir's published ports
  441. ansible.builtin.command:
  442. argv:
  443. - docker
  444. - container
  445. - port
  446. - matrix-bot-meowlnir
  447. register: matrix_bot_meowlnir_published_ports
  448. changed_when: false
  449. failed_when: false
  450. - name: Assert the role did not publish a host port
  451. ansible.builtin.assert:
  452. that:
  453. - matrix_bot_meowlnir_runtime.HostConfig.PortBindings | default({}, true) | length == 0
  454. - matrix_bot_meowlnir_published_ports.rc == 0
  455. - matrix_bot_meowlnir_published_ports.stdout | trim | length == 0
  456. fail_msg: >-
  457. Meowlnir unexpectedly publishes a host port:
  458. {{ matrix_bot_meowlnir_published_ports.stdout | default('unknown') }}
  459. success_msg: "The role leaves Meowlnir's HTTP port unpublished"
  460. - name: Assert Docker accepted the role's custom label
  461. ansible.builtin.assert:
  462. that:
  463. - matrix_bot_meowlnir_runtime.Config.Labels is mapping
  464. - matrix_bot_meowlnir_runtime.Config.Labels['molecule.meowlnir.coverage'] == 'enabled'
  465. fail_msg: "Docker did not attach the custom label from the role's label file"
  466. success_msg: "Docker accepted the role's custom label"