Skip to content

Commit ac819fd

Browse files
committed
fix: stop inventing an Arcane password and keep the seeded login
The role minted its own admin password, so the credentials on a provisioned box matched neither upstream's documentation nor anything a developer would guess. The login is now exactly what Arcane ships with, and the role sets neither the username nor the password. What it still does is retire the forced first-login prompt, which is the part worth automating. That needs a password submitted, because only a COMPLETED change clears the flag -- an admin-side user update sets the password and leaves it standing. So the change submits the seeded password as both the old and the new value: the flag drops and the credentials do not move. Upstream's default `strong` policy rejects its own seeded password (twelve characters, but no uppercase and no digit), so the policy is relaxed to `basic` first. Eight characters remains the floor regardless -- the request schema rejects anything shorter with a 422 before the policy is read, which is why a short password is not reachable by configuration at all. The admin is now located by its global-admin flag rather than by the name `arcane`, so a host whose admin was renamed is still found. soe_arcane_admin_password is gone. The one knob left is soe_arcane_password_policy, for putting the character-class requirements back. Verified by destroying the container, its volume and the stack directory on three hosts and installing clean. Each came up with username `arcane`, failed=0 and rescued=0, and a real login as arcane/arcane-admin returns 200 with requiresPasswordChange false from /api/auth/me -- the endpoint the UI itself calls, and the flag its root layout gates the change dialog on.
1 parent 12733eb commit ac819fd

3 files changed

Lines changed: 27 additions & 27 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ reports success -- the settings simply land where nobody sees them.
175175
- `contributor`: hyperi-ci and the tools its checks drive (semgrep, alint), gitleaks, trivy, hadolint, pip-audit, ansible-lint, pre-commit, act
176176
- `soe` / `soe-gui`: HyperI org policy: VPN clients, Claude Code, Slack, LibreOffice, RDP client, telemetry-disable, auto-updates, GNOME taskbar
177177
- `power-profile` (off by default, and deliberately not in `soe`): sleep, idle and lid policy, selected per machine. `always-on` (the default profile) never idle-suspends on mains power and does not sleep when the lid shuts -- for a repurposed laptop doing build work, or a desktop that has to answer ssh. `vm` never sleeps or suspends at all, for an unattended RDP guest that nobody can walk over and wake. Battery behaviour stays stock under `always-on`, because a machine that will not sleep in a bag cooks itself. Profiles are data files, so adding one is adding a file -- see [roles/power-profile/README.md](ansible/roles/power-profile/README.md)
178-
- `arcane` (off by default): [Arcane](https://getarcane.app), a web UI for the containers on the box. Enable it with `-e soe_arcane_enabled=true` and you get a daemon on `http://localhost:3552` that comes back after a reboot and keeps itself updated. Works against docker-ce on Linux and colima on macOS. Bound to loopback because it holds the Docker socket, so whatever reaches that port owns the machine. Login is `arcane` / `Arcane-Admin1!` (set `soe_arcane_admin_password` to change it -- Arcane requires at least 12 characters with an uppercase letter, a lowercase letter, a number and a symbol). Upstream forces a password change on first login; the role performs that change itself right after deploying, so you never meet the dialog. There is still a login -- auto-login is compiled out of every published image, so zero-auth is not available without building your own
178+
- `arcane` (off by default): [Arcane](https://getarcane.app), a web UI for the containers on the box. Enable it with `-e soe_arcane_enabled=true` and you get a daemon on `http://localhost:3552` that comes back after a reboot and keeps itself updated. Works against docker-ce on Linux and colima on macOS. Bound to loopback because it holds the Docker socket, so whatever reaches that port owns the machine. Login is whatever Arcane seeds -- `arcane` / `arcane-admin` as upstream documents it. The role sets neither, and only clears the forced first-login password prompt, which it does by re-submitting that seeded password so the credentials stay unchanged. That needs the password policy relaxed to `basic` (`soe_arcane_password_policy`), because upstream's default `strong` policy rejects its own seeded password. There is still a login -- auto-login sits behind a `buildables` Go build tag that no published image is compiled with, so zero-auth is not available without building your own image
179179
- `local-services` (off by default): a persistent local ClickHouse and Redpanda for ad-hoc work -- somewhere to poke at a query or hand-feed a topic without waiting for a suite to build. Enable with `-e soe_local_services_enabled=true`. Deployed **stopped**: `restart: no`, so a reboot leaves them down and they cost nothing until `local-services up`, which pulls latest and takes seconds. Both capped at 1GB and bound to loopback. They are spike instances -- integration and e2e suites create and tear down their own containers, because a shared daemon makes a suite non-hermetic and order-dependent
180180

181181
**Desktop UI** (`winlike` or `maclike` tag): GNOME extensions, a transparent taskbar (winlike) or a dock (maclike).

‎ansible/roles/soe/defaults/main.yml‎

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,15 @@ soe_arcane_auto_update_exclude:
3939
# abbreviation.
4040
soe_arcane_timezone: UTC
4141

42-
# Admin password, set once while the seeded credential is still known.
42+
# The login is whatever Arcane seeds -- this role sets neither the username nor
43+
# the password, so upstream's documented default is what you sign in with.
4344
#
44-
# Arcane seeds `arcane` / `arcane-admin` with a forced password change on first
45-
# login. The role performs that change itself straight after the first deploy,
46-
# which clears the flag, so nobody meets the dialog.
47-
#
48-
# Upstream's own seeded value cannot be reused here: the API enforces at least
49-
# 12 characters with an uppercase letter, a lowercase letter, a number and a
50-
# symbol, and rejects anything weaker with a 400. This is the seeded name in a
51-
# form that policy accepts.
52-
#
53-
# A known default rather than a generated secret: this is a loopback-only UI,
54-
# and a password the developer already knows beats one they have to go and look
55-
# up. Override it in group_vars on any machine where that trade does not hold.
56-
soe_arcane_admin_password: Arcane-Admin1!
45+
# Upstream's default policy is `strong`: 12 characters with an uppercase letter,
46+
# a number and a symbol, which its OWN seeded password fails. Retiring the
47+
# forced first-login prompt means re-submitting that seeded password, so the
48+
# policy has to accept it. Eight characters remains the floor whatever this
49+
# says -- the request schema rejects anything shorter before the policy is read.
50+
soe_arcane_password_policy: basic
5751

5852
# ============================================================================
5953
# Local services -- persistent ClickHouse + Redpanda for ad-hoc work, OPT-IN.

‎ansible/roles/soe/tasks/arcane.yml‎

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -176,34 +176,41 @@
176176
no_log: true
177177
when: not ansible_check_mode
178178

179+
# Selected by the global-admin flag rather than by name, so a host whose
180+
# admin has since been renamed is still found.
179181
- name: Work out whether Arcane still wants a password change
180182
# noqa: var-naming[no-role-prefix] -- soe_ IS the role prefix here
181183
ansible.builtin.set_fact:
182184
soe_arcane_admin: >-
183185
{{ (soe_arcane_users.json.data | default([])
184-
| selectattr('username', 'equalto', 'arcane')
186+
| selectattr('isGlobalAdmin', 'defined')
187+
| selectattr('isGlobalAdmin')
185188
| list | first) | default({}) }}
186189
when: not ansible_check_mode
187190

188-
# No currentPassword needed on the admin path, so this works whatever the
189-
# password happens to be now.
190-
- name: Set the Arcane admin password
191+
# Must precede the change below: the policy is read at validation time, and
192+
# the default `strong` rejects Arcane's own seeded password.
193+
- name: Relax the Arcane password policy
191194
ansible.builtin.uri:
192-
url: "http://127.0.0.1:{{ soe_arcane_port }}/api/users/{{ soe_arcane_admin.id }}"
195+
url: "http://127.0.0.1:{{ soe_arcane_port }}/api/environments/0/settings"
193196
method: PUT
194197
headers:
195198
X-Api-Key: "{{ soe_arcane_admin_api_key }}"
196199
body_format: json
197200
body:
198-
password: "{{ soe_arcane_admin_password }}"
201+
authPasswordPolicy: "{{ soe_arcane_password_policy }}"
199202
status_code: [200]
200-
register: soe_arcane_pwset
201-
changed_when: soe_arcane_pwset.status == 200
202-
no_log: true
203+
register: soe_arcane_policy
204+
changed_when: soe_arcane_policy.status == 200
203205
when:
204206
- not ansible_check_mode
205207
- soe_arcane_admin.requiresPasswordChange | default(false)
206208

209+
# Changing the seeded password to itself: the flag clears, and the login
210+
# stays the one upstream documents. `arcane-admin` is upstream's seed, not a
211+
# value this role chooses -- it is only ever submitted while the
212+
# forced-change flag is still up, which is before anyone could have changed
213+
# it.
207214
- name: Retire the forced password change
208215
ansible.builtin.uri:
209216
url: "http://127.0.0.1:{{ soe_arcane_port }}/api/auth/password"
@@ -212,12 +219,11 @@
212219
X-Api-Key: "{{ soe_arcane_admin_api_key }}"
213220
body_format: json
214221
body:
215-
currentPassword: "{{ soe_arcane_admin_password }}"
216-
newPassword: "{{ soe_arcane_admin_password }}"
222+
currentPassword: arcane-admin
223+
newPassword: arcane-admin
217224
status_code: [200]
218225
register: soe_arcane_pwchange
219226
changed_when: soe_arcane_pwchange.status == 200
220-
no_log: true
221227
when:
222228
- not ansible_check_mode
223229
- soe_arcane_admin.requiresPasswordChange | default(false)

0 commit comments

Comments
 (0)