spaceship-earth: per-host Multica PAT, root LV growth, headless Obsidian (WDWL-22)
- provision-agent-host.yml: multica_pat now comes from vault_multica_pats[inventory_hostname_short], one daemon-<host> token per host. A pre_task asserts the key exists (never prints the value) so a missing entry fails by host name instead of as a no_log "censored". - provision-wong-host.yml: spaceship-earth only. Grows the root partition, PV and LV/filesystem with growpart + community.general.lvg/lvol; idempotent (second run changed=0). Then applies obsidian_headless. - roles/obsidian_headless: Obsidian's official headless Sync client (obsidian-headless 0.0.14) as system user obsync under a sandboxed systemd unit with UMask=0077. Vault at /srv/obsidian/vault: everpure/ and wip/ obsync-only, inbox/ granted to multica via access + default ACLs, vault root traverse-only. Verifies the isolation as multica. Sign-in to Obsidian Sync stays manual (see the role README). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
04a0937910
commit
15aeb8e222
14 files changed
+634
-4
No files matched your search
@@ -0,0 +1,96 @@
|
||||
---
|
||||
# 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
|
||||
|
||||
# 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
|
||||
Reference in new issue
Block a user