From d05cfcf317c5bdeaab645dcbf9613de90171a237 Mon Sep 17 00:00:00 2001 From: Hermes Agent service account Date: Fri, 29 May 2026 21:38:44 -0500 Subject: [PATCH] fix(semaphore): provide SEMAPHORE_ADMIN_* env vars for non-interactive first boot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v2.18 image's entrypoint runs the setup wizard on first boot. Without the SEMAPHORE_ADMIN_* variables it prompts on stdin, fails with 'Username cannot be empty', and the container exits — leading to a crash loop. Set: SEMAPHORE_ADMIN=admin SEMAPHORE_ADMIN_NAME=Administrator SEMAPHORE_ADMIN_EMAIL=admin@local.mk-labs.cloud SEMAPHORE_ADMIN_PASSWORD={{ vault_semaphore_admin_password }} SEMAPHORE_PLAYBOOK_PATH=/var/lib/semaphore/playbooks The env-var bootstrap path is stable in v2.x; only the legacy 'semaphore user add' CLI invocation was unreliable. Drop the manual user-add step from the README. --- ansible/roles/semaphore/README.md | 24 +++++++++---------- ansible/roles/semaphore/tasks/verify.yml | 8 ++----- .../templates/semaphore.container.j2 | 10 ++++++++ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/ansible/roles/semaphore/README.md b/ansible/roles/semaphore/README.md index 9d8d7c8..1d6df3f 100644 --- a/ansible/roles/semaphore/README.md +++ b/ansible/roles/semaphore/README.md @@ -62,21 +62,21 @@ Or via the dedicated playbook: ansible-playbook -i inventory.yml playbooks/day1_deploy_semaphore.yml ``` -## First-run admin user creation (manual) +## First-run admin user -Semaphore's CLI `user add` is intentionally invoked once, by hand, after -the first deployment succeeds: +The container provisions the initial admin user from the +`SEMAPHORE_ADMIN_*` environment variables on first boot. Credentials: -```bash -sudo podman exec -it semaphore semaphore user add --admin \ - --login admin \ - --name "Administrator" \ - --email admin@local.mk-labs.cloud \ - --password '' -``` +| Field | Value | +|----------|------------------------------------------------| +| Login | `admin` | +| Name | `Administrator` | +| Email | `admin@local.mk-labs.cloud` | +| Password | `vault_semaphore_admin_password` (in vault) | -Subsequent password rotations should also be done via the CLI, not by -re-running this role. +The admin env vars are only consulted on first boot when no admin +exists in the database. Subsequent password rotations should be done +through the web UI, not by re-running this role. ## Pinned versions diff --git a/ansible/roles/semaphore/tasks/verify.yml b/ansible/roles/semaphore/tasks/verify.yml index 328264f..3ceea35 100644 --- a/ansible/roles/semaphore/tasks/verify.yml +++ b/ansible/roles/semaphore/tasks/verify.yml @@ -22,9 +22,5 @@ msg: >- Semaphore is reachable on http://127.0.0.1:{{ semaphore_listen_port }}. Public URL: {{ semaphore_web_url }}. - If this is the first deployment, create the admin user with: - sudo podman exec -it {{ semaphore_container_name }} \ - semaphore user add --admin \ - --login admin --name Administrator \ - --email admin@local.mk-labs.cloud \ - --password '' + Admin user 'admin' is provisioned automatically on first boot using + vault_semaphore_admin_password. diff --git a/ansible/roles/semaphore/templates/semaphore.container.j2 b/ansible/roles/semaphore/templates/semaphore.container.j2 index 3be3528..3a8f241 100644 --- a/ansible/roles/semaphore/templates/semaphore.container.j2 +++ b/ansible/roles/semaphore/templates/semaphore.container.j2 @@ -25,6 +25,16 @@ Environment=SEMAPHORE_DB={{ semaphore_db_name }} Environment=SEMAPHORE_DB_USER={{ semaphore_db_user }} Environment=SEMAPHORE_DB_PASS={{ semaphore_db_password }} +# First-boot admin user (used only during initial setup; subsequent +# password changes go through the web UI). +Environment=SEMAPHORE_ADMIN=admin +Environment=SEMAPHORE_ADMIN_PASSWORD={{ semaphore_admin_password }} +Environment=SEMAPHORE_ADMIN_NAME=Administrator +Environment=SEMAPHORE_ADMIN_EMAIL=admin@local.mk-labs.cloud + +# Playbook scratch directory inside the container +Environment=SEMAPHORE_PLAYBOOK_PATH=/var/lib/semaphore/playbooks + # Encryption for stored access keys (must be a 32-byte base64 string). Environment=SEMAPHORE_ACCESS_KEY_ENCRYPTION={{ semaphore_access_key_encryption }}