Semaphore injects environment secrets as ansible extra-vars, not as
process env vars, so lookup('env','OP_SERVICE_ACCOUNT_TOKEN') resolved
to empty string and the op CLI hung waiting for interactive auth.
Reference the variable directly instead.
delegate_to: localhost alone still uses SSH, which hangs on the
Semaphore controller. Add connection: local so the op tasks run in
the controller process directly.
The target host does not have the op CLI installed, so op invocations
must run on the Semaphore controller (delegate_to: localhost, become:
false — the controller runs rootless). Generated/loaded secrets also
leak into task logs on failure, so mark the three op tasks and the
set_fact tasks with no_log: true.
The command module validates args.chdir before honoring check mode, so
dry runs fail with ENOENT on the stack dir (file task only pretends to
create it). Gate Deploy stack on ansible_check_mode — dry runs should
not run docker compose up anyway.
Shell tasks are skipped in check mode by default, leaving op_item.stdout
empty and breaking from_json in the set_fact. The op item get calls are
read-only, so mark them check_mode: no so dry runs reflect reality.