diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dad27a52..18abe2872 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# 2026-10-30 + +## The base directory (`/matrix`) is now owned by root + +The playbook now makes the base directory (`matrix_base_data_path`, `/matrix` by default) and its `bin` directory owned by `root`, with the `matrix` group and the same mode (`0750`). Previously they were owned by the `matrix` user. + +Whoever owns this directory can rename any service's directory in it, even one owned by root, and put another in its place. A service that runs something as root from its directory relies on this not being possible. + +Nothing changes for you: the services' own directories keep their owners, and the `matrix` user can still reach them through the group. Re-running the playbook (`just install-all`) changes the owner. To keep the old owner, set `matrix_base_data_path_owner: "{{ matrix_user_name }}"` in your `vars.yml` file (not recommended). + # 2026-10-19 ## `just start-all` and `just start-group` restart all targeted services again diff --git a/roles/custom/matrix-base/defaults/main.yml b/roles/custom/matrix-base/defaults/main.yml index 1a3baf51f..6e64d920e 100644 --- a/roles/custom/matrix-base/defaults/main.yml +++ b/roles/custom/matrix-base/defaults/main.yml @@ -227,6 +227,11 @@ matrix_base_synology_volume_path: "/volume1" matrix_base_data_path: "/matrix" matrix_base_data_path_mode: "750" +# Owned by root: whoever owns it could rename any service's directory (even a root-owned one) and put another in its place. +# The group lets the matrix user reach the services' directories. +matrix_base_data_path_owner: root +matrix_base_data_path_group: "{{ matrix_group_name }}" + matrix_bin_path: "{{ matrix_base_data_path }}/bin" matrix_host_command_sleep: "/usr/bin/env sleep" diff --git a/roles/custom/matrix-base/tasks/setup_matrix_base.yml b/roles/custom/matrix-base/tasks/setup_matrix_base.yml index 7fc7148e7..b7c23cb26 100644 --- a/roles/custom/matrix-base/tasks/setup_matrix_base.yml +++ b/roles/custom/matrix-base/tasks/setup_matrix_base.yml @@ -13,21 +13,33 @@ --- -# Snapshot ownership before any changes so we can decide whether a recursive -# chown is needed (only when uid/gid actually differs from expected). +# On Synology, name-based chown works for directly-touched paths but leaves +# existing sub-paths with stale numeric ownership when uid/gid changes between +# runs. We recurse only when the base path's gid doesn't match, so normal runs +# skip the expensive tree walk entirely. Its uid is not compared, as the base path is owned by root, not the matrix user. +# The recursive chown runs before the base paths are ensured below, so they get their own ownership back. +# chown -R is used instead of the file module's recurse option to avoid Ansible iterating every entry in Python. - name: Check current ownership of Matrix base path (Synology) ansible.builtin.stat: path: "{{ matrix_base_data_path }}" register: matrix_base_data_path_stat when: matrix_base_host_is_synology +- name: Ensure Matrix base path ownership is correct using numeric UID/GID (Synology) + ansible.builtin.command: chown -R {{ matrix_user_uid }}:{{ matrix_user_gid }} {{ matrix_base_data_path }} + changed_when: true + when: >- + matrix_base_host_is_synology and + matrix_base_data_path_stat.stat.exists and + matrix_base_data_path_stat.stat.gid | int != matrix_user_gid | int + - name: Ensure Matrix base paths exists ansible.builtin.file: path: "{{ item }}" state: directory mode: "{{ matrix_base_data_path_mode }}" - owner: "{{ matrix_user_name }}" - group: "{{ matrix_group_name }}" + owner: "{{ matrix_base_data_path_owner }}" + group: "{{ matrix_base_data_path_group }}" with_items: - "{{ matrix_base_data_path }}" - "{{ matrix_bin_path }}" @@ -37,18 +49,3 @@ src: "{{ role_path }}/templates/bin/remove-all.j2" dest: "{{ matrix_bin_path }}/remove-all" mode: '0750' - -# On Synology, name-based chown works for directly-touched paths but leaves -# existing sub-paths with stale numeric ownership when uid/gid changes between -# runs. We recurse only when the pre-task uid/gid didn't match, so normal runs -# skip the expensive tree walk entirely. chown -R is used instead of the file -# module's recurse option to avoid Ansible iterating every entry in Python. -- name: Ensure Matrix base path ownership is correct using numeric UID/GID (Synology) - ansible.builtin.command: chown -R {{ matrix_user_uid }}:{{ matrix_user_gid }} {{ matrix_base_data_path }} - changed_when: true - when: >- - matrix_base_host_is_synology and ( - not matrix_base_data_path_stat.stat.exists or - matrix_base_data_path_stat.stat.uid | int != matrix_user_uid | int or - matrix_base_data_path_stat.stat.gid | int != matrix_user_gid | int - )