Files
computer-playbook/roles/web-app-mastodon/tasks/05_administrator.yml
kevinveenbirkenbachandClaude Opus 5 5dd1f331f8 fix(mastodon): let the tootctl failure speak without leaking the password
no_log on the create task is right: tootctl prints "New password: #{password}"
on stdout when it succeeds. It also suppresses the syslog record, so a failure
left nothing anywhere. The rescue bundle for run 33574056480 carries the
neighbouring unblock task with its whole Ruby script and no trace of this one.

The failure path is a different stream. report_errors goes through
fail_with_message, which raises Thor::Error, and Thor writes that to stderr,
after the create has already given up on generating anything. Quoting stderr
therefore costs no secret.

The task now records without judging, and an assert decides. It reads the
already-existing case from either stream rather than stderr alone, which is
hardening rather than the fix: the source shows Thor puts it on stderr, so the
old condition would have tolerated it and the account being taken was never
what failed here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 18:32:10 +02:00

44 lines
2.3 KiB
YAML

---
- name: 🧹 Unblock the administrator username
ansible.builtin.shell: > # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
container exec -i -u root
-e MASTODON_ADMIN_USERNAME={{ lookup('users', 'administrator').username | quote }}
{{ MASTODON_LOCAL_CID | quote }}
bundle exec rails runner -
args:
stdin: "{{ lookup('file', 'ruby/unblock_admin_username.rb') }}"
register: mastodon_unblock
changed_when: "'Unblocked 0 ' not in mastodon_unblock.stdout"
- name: 📁 Create admin account via tootctl
ansible.builtin.shell: > # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
container exec -u root {{ MASTODON_LOCAL_CID | quote }} bash -c
"bin/tootctl accounts create {{ lookup('users', 'administrator').username }}
--email {{ lookup('users', 'administrator').email }}
--confirmed --role Owner"
register: tootctl_create
changed_when: tootctl_create.rc == 0
failed_when: false
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: 🛑 Refuse a tootctl error other than the account already existing
ansible.builtin.assert:
that:
- tootctl_create.rc == 0 or 'taken' in tootctl_create.stdout | lower or 'taken' in tootctl_create.stderr | lower
fail_msg: >-
bin/tootctl accounts create exited {{ tootctl_create.rc }} for the administrator
account without reporting the name as taken: {{ tootctl_create.stderr }}
- name: 👍 Approve the administrator account in Mastodon
ansible.builtin.shell: > # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
container exec -u root {{ MASTODON_LOCAL_CID | quote }} bash -c "bin/tootctl accounts modify {{ lookup('users', 'administrator').username }} --approve"
register: tootctl_approve
changed_when: false
# rationale: async; approvals run overlapped, reaped below before the login spec
async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}"
poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}"
- name: "⏳ Reap the Mastodon admin approval"
ansible.builtin.include_tasks: utils/async/reap.yml
vars:
async_reap_jobs: "{{ tootctl_approve.results | default([tootctl_approve]) }}"
async_reap_label: "Mastodon administrator approval"
async_reap_tolerate: []