Files
computer-playbook/roles/web-app-penpot/tasks/01_administrator.yml
kevinveenbirkenbachandClaude Opus 5.5 93cbd2045e fix(web-app-penpot): pass the administrator password on stdin
manage.py create-profile and update-profile parse their options with
argparse, and `-p <value>` reads a value that starts with `-` as the next
option. A generated password with a leading dash therefore fails both
commands with exit 2 ("argument -p/--password: expected one argument")
before they reach the backend, and the bootstrap task retries until it
gives up. On main this broke the guide run of Penpot#2 in run
39668792538: the Docker events of the rescue snapshot show eight
create-profile execs ending with exit 2 while the backend was healthy
and its prepl received no call.

Without -p, manage.py reads the password with getpass, which falls back
to stdin when the exec has no TTY. Both tasks now feed the password to
`container exec -i` on stdin. This also keeps the password out of the
exec command line, which Docker writes into its event stream and
therefore into the rescue diagnostics artifacts.

The password-quote lint masked only block `stdin: |` / `stdin: >`
values and flagged the inline `stdin: "{{ PENPOT_ADMIN_PASSWORD }}"` as
an unquoted password in a shell command. stdin never reaches a shell, so
the lint now masks every `stdin:` form; an unquoted password in `cmd`
is still reported.

Fixes #1139

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 17:41:43 +02:00

42 lines
2.0 KiB
YAML

---
- name: "🔍 Resolve the node that holds the Penpot backend and its local id"
ansible.builtin.include_tasks: "{{ lookup('path_absolute', 'roles/sys-svc-compose/tasks/utils/swarm/resolve_host_cid.yml') }}"
vars:
resolve_service_key: "{{ PENPOT_BACKEND_SERVICE }}"
resolve_output_prefix: PENPOT_BACKEND
resolve_compose_cid: "{{ PENPOT_BACKEND_CONTAINER_ADDRESS }}"
- name: "🥾 Bootstrap the Penpot administrator's local account (idempotent)"
ansible.builtin.shell:
cmd: >- # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
container exec -i {{ PENPOT_BACKEND_LOCAL_CID | quote }}
python3 manage.py create-profile
-n {{ PENPOT_ADMIN_FULLNAME | quote }}
-e {{ PENPOT_ADMIN_EMAIL | quote }}
stdin: "{{ PENPOT_ADMIN_PASSWORD }}"
register: penpot_admin_create
retries: 30
delay: 5
until: >-
penpot_admin_create.rc == 0 or
('already exists' in (penpot_admin_create.stdout | default('') ~ penpot_admin_create.stderr | default('')))
changed_when: "'Created' in penpot_admin_create.stdout"
failed_when:
- penpot_admin_create.rc != 0
- "'already exists' not in (penpot_admin_create.stdout | default('') ~ penpot_admin_create.stderr | default(''))"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
delegate_to: "{{ PENPOT_BACKEND_HOST_NODE }}"
- name: "🔧 Set the Penpot administrator's local password when the profile already exists"
ansible.builtin.shell:
cmd: >- # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
container exec -i {{ PENPOT_BACKEND_LOCAL_CID | quote }}
python3 manage.py update-profile
-e {{ PENPOT_ADMIN_EMAIL | quote }}
stdin: "{{ PENPOT_ADMIN_PASSWORD }}"
when: "'already exists' in (penpot_admin_create.stdout | default('') ~ penpot_admin_create.stderr | default(''))"
register: penpot_admin_update
changed_when: "'Updated' in penpot_admin_update.stdout"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
delegate_to: "{{ PENPOT_BACKEND_HOST_NODE }}"