--- # Permission model # # / obsync 0710 + user::--x traverse, no listing # / obsync 0710 + user::--x traverse, no listing # // obsync 0700 nobody else # // obsync 0770 + user::rwx and user:obsync:rwx, # each also as a DEFAULT entry, so new # children inherit both # # The user:obsync entry matters for content the SHARED user creates: that is # owned :, so without a named entry obsync falls into "other" (---) # and Sync can neither read nor upload it. # # The owning group is obsync's private group, so its bits grant nobody. On a # directory that carries an ACL, the group bits of the mode ARE the ACL mask, # which is why the modes here are 0710/0770 rather than 0700: a 0700 chmod # would zero the mask and silently void every named entry. # # Anything else in the vault (folders Sync creates later, .obsidian/) is born # private: the service runs with UMask=0077, and the umask is ignored only # under a directory that has a default ACL — i.e. only in the shared folders. - name: Layout | Collect the users granted shared folders ansible.builtin.set_fact: _obh_shared_users: "{{ obsidian_headless_shared_folders | map(attribute='user') | unique | list }}" - name: Layout | Create the vault and its parent ansible.builtin.file: path: "{{ item }}" state: directory owner: "{{ obsidian_headless_user }}" group: "{{ obsidian_headless_group }}" mode: "{{ '0710' if _obh_shared_users | length > 0 else '0700' }}" loop: - "{{ obsidian_headless_vault_path | dirname }}" - "{{ obsidian_headless_vault_path }}" - name: Layout | Let shared users traverse (not list) the vault and its parent ansible.posix.acl: path: "{{ item.0 }}" entity: "{{ item.1 }}" etype: user permissions: x state: present loop: >- {{ [obsidian_headless_vault_path | dirname, obsidian_headless_vault_path] | product(_obh_shared_users) | list }} - name: Layout | Create the private folders ansible.builtin.file: path: "{{ obsidian_headless_vault_path }}/{{ item }}" state: directory owner: "{{ obsidian_headless_user }}" group: "{{ obsidian_headless_group }}" mode: "0700" loop: "{{ obsidian_headless_private_folders }}" - name: Layout | Create the shared folders ansible.builtin.file: path: "{{ obsidian_headless_vault_path }}/{{ item.path }}" state: directory owner: "{{ obsidian_headless_user }}" group: "{{ obsidian_headless_group }}" mode: "0770" loop: "{{ obsidian_headless_shared_folders }}" loop_control: label: "{{ item.path }}" # Each shared folder gets its user AND the service user, both as access and # default entries. - name: Layout | Build the shared-folder grants ansible.builtin.set_fact: _obh_grants: >- {{ (obsidian_headless_shared_folders + (obsidian_headless_shared_folders | map(attribute='path') | map('community.general.dict_kv', 'path') | list | map('combine', {'user': obsidian_headless_user}) | list)) | unique | list }} - name: Layout | Grant shared folders (access and default entries) ansible.posix.acl: path: "{{ obsidian_headless_vault_path }}/{{ item.0.path }}" entity: "{{ item.0.user }}" etype: user permissions: rwx default: "{{ item.1 }}" state: present loop: "{{ _obh_grants | product([false, true]) | list }}" loop_control: label: "{{ item.0.path }} -> {{ item.0.user }}{{ ' (default)' if item.1 else '' }}"