Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ flowchart TD
| `vpn-clients` | OpenVPN 3, WireGuard, Tunnelblick (macOS) |
| `vm` | VM guest optimisations (QEMU/SPICE agents) |
| `power-profile` | Sleep/idle/lid policy. `always-on` (default) or `vm`, via `-e power_profile=<name>` |
| `arcane` | Arcane container UI, localhost-only. Off unless `-e soe_arcane_enabled=true` |
| `arcane` | Arcane container UI, localhost-only. Off unless `-e soe_arcane_enabled=true`. Add `-e soe_arcane_long_session=true` for a year-long login |
| `local-services` | Persistent local ClickHouse + Redpanda for spikes. Off unless `-e soe_local_services_enabled=true` |

### Remote Login is not Desktop Sharing
Expand Down Expand Up @@ -175,7 +175,7 @@ reports success -- the settings simply land where nobody sees them.
- `contributor`: hyperi-ci and the tools its checks drive (semgrep, alint), gitleaks, trivy, hadolint, pip-audit, ansible-lint, pre-commit, act, and git-scrub for rewriting AI residue or a leaked secret out of git history -- gitleaks scans FULL history, so a secret removed from HEAD still fails the gate. macbash is here too: it flags the GNU-only bash constructs that break on macOS, and CONTRIBUTING.md asks for it on every shell change
- `soe` / `soe-gui`: HyperI org policy: VPN clients, Claude Code, Slack, LibreOffice, RDP client, telemetry-disable, auto-updates, GNOME taskbar
- `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)
- `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
- `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. The login lasts about a day by default, which is a prompt every morning on a dev box -- `-e soe_arcane_long_session=true` stretches it to a year from each login. It is off by default because Arcane holds the Docker socket, and it takes one log-out and log-in to take effect, since the session expiry is stamped at login
- `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

**Desktop UI** (`winlike` or `maclike` tag): GNOME extensions, a transparent taskbar (winlike) or a dock (maclike).
Expand Down
19 changes: 19 additions & 0 deletions ansible/roles/soe/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,25 @@ soe_arcane_timezone: UTC
# says -- the request schema rejects anything shorter before the policy is read.
soe_arcane_password_policy: basic

# Arcane's default login lasts about a day. Two knobs move that and BOTH are
# needed -- either alone still logs you out.
#
# soe_arcane_session_timeout_minutes sets the access token's life, and the
# access-token cookie is the only thing that survives a browser restart. The
# server clamps it to 15..525600 minutes and has no never-expire value, so a
# year from each login is the practical ceiling.
#
# soe_arcane_refresh_expiry stamps the session row's expiry at login and is
# never extended on refresh, so leaving it at the image's 168h means every
# request 401s at day seven whatever the timeout says.
#
# Off by default: Arcane holds the Docker socket, so a year-long cookie is a
# per-machine decision. Both settings stay ABSENT while the flag is off, rather
# than being written at a default, so a value set by hand in the UI survives.
soe_arcane_long_session: false
soe_arcane_session_timeout_minutes: 525600
soe_arcane_refresh_expiry: 87600h

# ============================================================================
# Local services -- persistent ClickHouse + Redpanda for ad-hoc work, OPT-IN.
# ============================================================================
Expand Down
25 changes: 18 additions & 7 deletions ansible/roles/soe/tasks/arcane.yml
Original file line number Diff line number Diff line change
Expand Up @@ -234,17 +234,22 @@
| map(attribute='value'))) }}
when: not ansible_check_mode

- name: Work out the auto-update settings this host should have
# authSessionTimeout is added only when the long session is opted into, so a
# run with the flag off leaves whatever is there rather than stamping a
# default over a value set by hand in the UI.
- name: Work out the settings this host should have
# noqa: var-naming[no-role-prefix] -- soe_ IS the role prefix here
ansible.builtin.set_fact:
soe_arcane_settings_want:
autoUpdate: "{{ soe_arcane_auto_update | bool | lower }}"
autoUpdateExcludedContainers: "{{ soe_arcane_auto_update_exclude | join(',') }}"
soe_arcane_settings_want: >-
{{ {'autoUpdate': soe_arcane_auto_update | bool | lower,
'autoUpdateExcludedContainers': soe_arcane_auto_update_exclude | join(',')}
| combine({'authSessionTimeout': soe_arcane_session_timeout_minutes | string}
if soe_arcane_long_session | bool else {}) }}

# `autoUpdate` is a database setting rather than an environment override, so
# asserting it needs the API. Values are strings upstream, not booleans.
# These are database settings rather than environment overrides, so asserting
# them needs the API. Values are strings upstream, not booleans or numbers.
# Only PUT on a real difference, otherwise every run reports changed.
- name: Assert Arcane's auto-update settings
- name: Assert Arcane's managed settings
ansible.builtin.uri:
url: "http://127.0.0.1:{{ soe_arcane_port }}/api/environments/0/settings"
method: PUT
Expand Down Expand Up @@ -273,6 +278,12 @@
There is still a login: auto-login sits behind a `buildables` Go build
tag that no published image is compiled with.

{% if soe_arcane_long_session %}
Long sessions are on ({{ soe_arcane_session_timeout_minutes }} minutes).
Log out and back in once -- the session expiry is stamped at login, so
the session you are already in keeps its old one.
{% endif %}

Stack: {{ soe_arcane_dir }}
Updates: hyperi-update pulls and recreates it; Arcane's own updater
keeps the containers it manages current.
Expand Down
5 changes: 5 additions & 0 deletions ansible/roles/soe/templates/arcane.env.j2
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,8 @@ TZ={{ soe_arcane_timezone }}
ENCRYPTION_KEY={{ soe_arcane_encryption_key }}
JWT_SECRET={{ soe_arcane_jwt_secret }}
ADMIN_STATIC_API_KEY={{ soe_arcane_admin_api_key }}
{% if soe_arcane_long_session %}
# Only present when soe_arcane_long_session is on. Absent, the image's own 168h
# applies and every session dies at day seven.
JWT_REFRESH_EXPIRY={{ soe_arcane_refresh_expiry }}
{% endif %}
2 changes: 1 addition & 1 deletion docs/install-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ hyperi-ci.
| LibreOffice (org office suite) | Linux | distro repo |
| Nemo, GNOME extensions (gext), fonts | Linux | distro / uv-tool / vendored |
| colima + Apple `container` (macOS only) | macOS | brew / github-binary |
| Arcane container UI (opt-in `soe_arcane_enabled`) | all | container image |
| Arcane container UI (opt-in `soe_arcane_enabled`; `soe_arcane_long_session` for a year-long login) | all | container image |
| Local ClickHouse + Redpanda (opt-in `soe_local_services_enabled`) | all | container image |
| removals / update_command / admin-scripts (opt-in `never`, on for soe) | Linux | tombstones + scripts |

Expand Down
3 changes: 2 additions & 1 deletion install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,8 @@ HyperI SOE (soe, soe-gui) - org policy, includes everything above:
forgejo/codeberg tea (Forgejo/Gitea CLI)
colima macOS container daemon + Apple container (macOS only)
arcane Container management UI, localhost-only (OPT-IN:
-e soe_arcane_enabled=true)
-e soe_arcane_enabled=true; add
-e soe_arcane_long_session=true for a year-long login)
local-services Persistent local ClickHouse + Redpanda for spikes,
deployed stopped (OPT-IN:
-e soe_local_services_enabled=true)
Expand Down
Loading