--- # Each check runs AS the user it is about, because file modes and ACLs only # mean something when exercised. Probes are cleaned up; nothing is left behind. - name: Verify | Shared users can write, read and delete in their folders ansible.builtin.command: argv: - /bin/sh - -c - 'f="$1/.obh-verify.$$"; echo ok > "$f" && grep -q ok "$f" && rm -f "$f"' - sh - "{{ obsidian_headless_vault_path }}/{{ item.path }}" become: true become_user: "{{ item.user }}" loop: "{{ obsidian_headless_shared_folders }}" loop_control: label: "{{ item.user }} -> {{ item.path }}" changed_when: false check_mode: false # The reverse direction: what the shared user writes, Sync must be able to # read (to upload it) and rewrite (to merge remote edits into it). - name: Verify | Content a shared user creates stays usable by the service (create) ansible.builtin.command: argv: - /bin/sh - -c - 'd="$1/.obh-verify-rev"; mkdir -p "$d" && echo ok > "$d/note.md"' - sh - "{{ obsidian_headless_vault_path }}/{{ item.path }}" become: true become_user: "{{ item.user }}" loop: "{{ obsidian_headless_shared_folders }}" loop_control: label: "{{ item.user }} -> {{ item.path }}" changed_when: false check_mode: false - name: Verify | Content a shared user creates stays usable by the service (use) ansible.builtin.command: argv: - /bin/sh - -c - 'd="$1/.obh-verify-rev"; grep -q ok "$d/note.md" && echo more >> "$d/note.md" && echo ok > "$d/reply.md"' - sh - "{{ obsidian_headless_vault_path }}/{{ item.path }}" become: true become_user: "{{ obsidian_headless_user }}" loop: "{{ obsidian_headless_shared_folders }}" loop_control: label: "{{ item.path }}" register: _obh_reverse changed_when: false failed_when: false check_mode: false - name: Verify | Remove the reverse probes ansible.builtin.file: path: "{{ obsidian_headless_vault_path }}/{{ item.path }}/.obh-verify-rev" state: absent loop: "{{ obsidian_headless_shared_folders }}" loop_control: label: "{{ item.path }}" changed_when: false - name: Verify | The service can read and rewrite shared users' content ansible.builtin.assert: that: - _obh_reverse.results | rejectattr('rc', 'equalto', 0) | list | length == 0 fail_msg: >- {{ obsidian_headless_user }} cannot read or write content a shared user created; Sync would never upload it. Check the user:{{ obsidian_headless_user }} default ACL entry on the shared folder. quiet: true # Simulates the service: obsync, umask 0077, creating a folder and a file the # way Sync does. The shared user must still reach both, via the default ACL. - name: Verify | Content the service creates in a shared folder inherits the grant (create) ansible.builtin.command: argv: - /bin/sh - -c - 'umask 0077; d="$1/.obh-verify-dir"; mkdir -p "$d" && echo ok > "$d/note.md"' - sh - "{{ obsidian_headless_vault_path }}/{{ item.path }}" become: true become_user: "{{ obsidian_headless_user }}" loop: "{{ obsidian_headless_shared_folders }}" loop_control: label: "{{ item.path }}" changed_when: false check_mode: false - name: Verify | Content the service creates in a shared folder inherits the grant (use) ansible.builtin.command: argv: - /bin/sh - -c - 'd="$1/.obh-verify-dir"; grep -q ok "$d/note.md" && echo ok > "$d/reply.md"' - sh - "{{ obsidian_headless_vault_path }}/{{ item.path }}" become: true become_user: "{{ item.user }}" loop: "{{ obsidian_headless_shared_folders }}" loop_control: label: "{{ item.user }} -> {{ item.path }}" register: _obh_inherit changed_when: false failed_when: false check_mode: false - name: Verify | Remove the inheritance probes ansible.builtin.file: path: "{{ obsidian_headless_vault_path }}/{{ item.path }}/.obh-verify-dir" state: absent loop: "{{ obsidian_headless_shared_folders }}" loop_control: label: "{{ item.path }}" changed_when: false - name: Verify | Inheritance held ansible.builtin.assert: that: - _obh_inherit.results | rejectattr('rc', 'equalto', 0) | list | length == 0 fail_msg: >- A shared user could not read or write content created by {{ obsidian_headless_user }} under umask 0077; the default ACL is not being inherited. quiet: true # Every shared user must be refused: listing the vault root, and listing, # reading into or writing into each private folder. - name: Verify | Shared users are denied the vault root listing and every private folder ansible.builtin.command: argv: >- {{ ['/bin/sh', '-c', _obh_deny_script, 'sh', obsidian_headless_vault_path] + obsidian_headless_private_folders }} vars: _obh_deny_script: | v="$1"; shift ls "$v" >/dev/null 2>&1 && { echo "can list $v"; exit 1; } for p in "$@"; do ls "$v/$p" >/dev/null 2>&1 && { echo "can list $p"; exit 1; } touch "$v/$p/.obh-verify" 2>/dev/null && { rm -f "$v/$p/.obh-verify"; echo "can write $p"; exit 1; } done exit 0 become: true become_user: "{{ item }}" loop: "{{ obsidian_headless_shared_folders | map(attribute='user') | unique | list }}" changed_when: false check_mode: false