Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
130 commits
Select commit Hold shift + click to select a range
462cf54
trigger ci
cyberb May 11, 2026
43214ce
phase 1: server CRUD + sqlite persistence
cyberb May 11, 2026
bcfcc2e
phase 2: process management (start/stop/restart)
cyberb May 11, 2026
e2902fc
phase 3+4: steamcmd vendor + pelican egg consumer + install endpoint
cyberb May 11, 2026
8f982e6
phase 5+6: log buffer + A2S server query
cyberb May 11, 2026
a026a22
phase 7-9: OIDC client registration, playwright e2e, CLAUDE.md docs
cyberb May 11, 2026
50692d3
fix: add selenium to test requirements (syncloudlib.integration.conft…
cyberb May 11, 2026
af2f84f
fix: auth on /api/, add authelia-basic nginx config
cyberb May 11, 2026
807b7ec
ci: drop buster (mirror owntracks 8089a34, bookworm-only)
cyberb May 11, 2026
9167211
ui: lockfile + Basic Auth + drop apt --with-deps
cyberb May 12, 2026
ad32c7b
ci: revert / to cookie auth, drop UI test steps (todo phase 8b)
cyberb May 12, 2026
8ae061f
ci: re-trigger after secrets added
cyberb May 12, 2026
2f38934
phase 4b: real teeworlds install + start + UDP probe in CI
cyberb May 12, 2026
9f8d479
phase 3b: real HLDS install via SteamCMD with bundled 32-bit libs
cyberb May 12, 2026
1d14813
fix: surface install errors in journal + last_error db field
cyberb May 12, 2026
3f7594c
fix steamcmd/build.sh: skip subdirs (gconv) when copying lib32 *.so*
cyberb May 12, 2026
a5c0418
fix: teeworlds asset is .tar.gz, support both .tar.gz and .tar.xz
cyberb May 12, 2026
9bf859f
fix: teeworlds uses 'sv_port N' config arg, not '-p N'; pass server.p…
cyberb May 12, 2026
443ed70
phase 3b take 2: bulk-bundle i386 libs (libssl3 etc.) for steamcmd HTTPS
cyberb May 12, 2026
bbb79c5
fix: steamcmd PWD must be SCDIR not HOME; capture steam logs in teardown
cyberb May 12, 2026
5564dc4
fix: copy steamcmd to writable runtime dir; /snap is read-only
cyberb May 12, 2026
06ef9f1
installer: +app_set_config 90 mod cstrike for HLDS-CS
cyberb May 12, 2026
ab4503a
fix: copy entire steamcmd bundle (public/, linux32/, etc.) to runtime…
cyberb May 12, 2026
9598d42
fix: pin teeworlds URL, drop GitHub API (rate-limited 60/hr unauth)
cyberb May 12, 2026
c001efe
xfail HLDS test pending steamcmd bootstrap diagnosis
cyberb May 12, 2026
7bfe2a6
phase 3c: bundle amd64 lib64 too — snap is now host-lib-independent
cyberb May 12, 2026
3002748
test: add steamcmd_diagnostics — capture ldd/LD_DEBUG/DNS/TLS before …
cyberb May 12, 2026
4d79d94
docs: update CLAUDE.md for lib64 bundle, runtime dir, phase status
cyberb May 12, 2026
4245f56
phase 3b RCA: exec steamcmd from $RUNTIME, not /snap
cyberb May 12, 2026
926f626
phase 3b RCA #2: prepend linux32/ to library path — Steam ships its o…
cyberb May 12, 2026
09cf483
diag: add strace + df + ulimit to steamcmd diagnostics
cyberb May 12, 2026
01b50f4
diag: fix the diag — seed runtime first, correct strace syscall names…
cyberb May 12, 2026
033b207
diag: simplify, no parens in echo args (bash was choking)
cyberb May 12, 2026
f79c771
fix: chown RUNTIME to game-server when wrapper is invoked as root
cyberb May 12, 2026
4571d78
diag: bundle i386 curl + use 'sudo -u -H bash -c' (game-server shell=…
cyberb May 12, 2026
c67c753
phase 3b RCA #3: patchelf interpreter so /proc/self/exe is in writabl…
cyberb May 12, 2026
c042daa
cleanup: patchelf to /snap path directly, drop runtime symlink
cyberb May 12, 2026
3535224
diag: trace wrapper exit + sanity-check interpreter before exec
cyberb May 12, 2026
3ad12b3
revert to interpreter path, plus runtime symlink
cyberb May 12, 2026
e004cbe
fix: copy (not symlink) ld-linux.so.2 into runtime — kernel can't tra…
cyberb May 12, 2026
47d5209
fix: hoist ld-linux.so.2 copy out of first-run guard
cyberb May 12, 2026
2785bc5
diag: stat the actual interpreter target + ls runtime/linux32 + check…
cyberb May 13, 2026
d8e249a
diag: extract real PT_INTERP from binary + realpath the loader
cyberb May 13, 2026
7176b22
diag: try running both copies of ld-linux directly to see which one i…
cyberb May 13, 2026
3674003
diag: dump binary's PT_INTERP bytes + try explicit ld-linux exec
cyberb May 13, 2026
31b9c2e
phase 3b RCA #4 (final): invoke RUNTIME copy of ld-linux explicitly
cyberb May 13, 2026
652edba
hlds: -insecure +sv_lan 1 — skip Steam auth that's not reachable in snap
cyberb May 13, 2026
43b0acd
phase 3b: split HLDS test — install passes, start+A2S xfail'd
cyberb May 13, 2026
05b3dc2
hlds: +app_update 90 -beta steam_legacy — Valve retired the default b…
cyberb May 13, 2026
3600c94
phase 10: catalog from upstream sources at build time
cyberb May 13, 2026
498a4df
fix catalog/build.sh: use tar --strip-components=1 (pelican tarball e…
cyberb May 13, 2026
c6f75ac
installer: accept 'pelican' and 'parkervcp' as egg sources (from new …
cyberb May 13, 2026
a46ae5a
phase 13: ui — pages, router, tier filter, server detail with logs, s…
cyberb May 13, 2026
ce16fd6
phase 11: bundle Eclipse Temurin OpenJDK 17 JRE headless (~45MB)
cyberb May 13, 2026
5bd9cab
phase 12: Steam paid account login via /api/v1/steam/login
cyberb May 13, 2026
eaab6fe
phase 14: Playwright auth helper + reenable test-ui in CI
cyberb May 13, 2026
6aea6ad
fix: pin @playwright/test to 1.59.1 (matches docker image)
cyberb May 13, 2026
28a57b2
ui-test: try multiple selectors for Authelia login + dump URL on failure
cyberb May 13, 2026
e4a33ea
ui-tests: tier filter — use hlds-cs (supported), teeworlds (compatibl…
cyberb May 13, 2026
e8337fa
ui-test: wait for URL change before asserting detail-name; upload Pla…
cyberb May 13, 2026
60b2f6c
ci/ui.sh: upload playwright-report + test-results to drone artifact
cyberb May 13, 2026
c0d460e
fix: use explicit /servers/:id path string, surface errors
cyberb May 13, 2026
f5bb30c
ui-test: assert detail element (hash router doesn't fire load event);…
cyberb May 13, 2026
aed3396
rename: game-server -> games, move installs to /data/games/servers
cyberb May 13, 2026
97ae4e1
trigger ci after rename
cyberb May 13, 2026
cd26a7a
phase 16+17: mobile bottom-bar nav + Minecraft e2e install test
cyberb May 13, 2026
2485f3e
phase 17 (real): add minecraft e2e install test (was missing from pre…
cyberb May 13, 2026
9a6edb6
fix: runner sets HOME=workDir for spawned games
cyberb May 14, 2026
a975e05
phase 18: real OIDC code+PKCE flow, backend session middleware, drop …
cyberb May 14, 2026
97b9c40
phase 19: CI go 1.25, full minecraft cycle, mobile nav polish
cyberb May 14, 2026
794c80a
phase 20: SVG icons → source assets, drop dead nginx auth_request sca…
cyberb May 14, 2026
c04481b
ui-e2e: wait for SPA-driven redirect to auth.<domain> before looking …
cyberb May 14, 2026
76e9314
auth: skip TLS verify for OIDC discovery against the internal Authelia
cyberb May 14, 2026
8169a5e
auth: trust syncloud CA properly (drop InsecureSkipVerify)
cyberb May 14, 2026
63911f5
auth: fix Authelia auth-request URL — drop the spurious /basic suffix
cyberb May 14, 2026
19259a7
ui-mobile: keep bottom-bar above scrolled content + anchor-scroll fixes
cyberb May 14, 2026
11daa59
web: MirageJS dev stub for npm run dev:stub
cyberb May 14, 2026
5248830
ui-mobile-nav: force-click on bottom-tabs + pointer-events:none on in…
cyberb May 14, 2026
4dc3187
test: retry hlds_cs_real_install — steamcmd flakes on 'Steam can't wr…
cyberb May 14, 2026
1ba4b7d
ci: per-distro binary smoke tests on bookworm + buster
cyberb May 14, 2026
7f4c6a5
ui: rename tier 'supported' → 'verified' + fix mobile-bar/settings ov…
cyberb May 14, 2026
2994198
ui: fix Settings mobile — .mobile-only used flex on a multi-row <sect…
cyberb May 14, 2026
4f0a567
ui: brand as 'Syncloud Game Hub' with the official Syncloud logo
cyberb May 14, 2026
24c7ed3
ui: replace window.confirm() delete prompts with styled ConfirmDialog
cyberb May 14, 2026
632a845
ci: split binary tests into one loop per tool, drop std.flattenArrays
cyberb May 14, 2026
f49ecf7
ci: each tool's binary tests sit directly under its build
cyberb May 14, 2026
ef3fd75
ci: extract inline cli build into cli/build.sh
cyberb May 14, 2026
bc79fce
steamcmd/test.sh: drive the real bin/steamcmd.sh wrapper
cyberb May 14, 2026
caaf18e
steamcmd/test.sh: copy bin/steamcmd.sh into build/snap/bin before inv…
cyberb May 14, 2026
c56eaf2
steamcmd: own bin/steamcmd.sh in the component dir
cyberb May 14, 2026
e4a0d27
steamcmd/test.sh: invoke wrapper as games user, matching prod
cyberb May 14, 2026
6707b91
steamcmd: pre-bootstrap at build, run from RO /snap, pin tarball sha
cyberb May 14, 2026
bf97044
strip comments — code speaks, comments were noise
cyberb May 14, 2026
90ac5c8
gitignore: .claude/ harness state
cyberb May 14, 2026
0d42b89
steamcmd: drop sha pin — every build pulls latest, CI gates it
cyberb May 14, 2026
ccad92a
steamcmd: hardcode HOME, drop HOME_OVERRIDE indirection
cyberb May 14, 2026
473a237
steamcmd: drop SSL_CERT_FILE — system trust store already has synclou…
cyberb May 14, 2026
8582ad6
auth: route basic-auth delegation through the Authelia unix socket
cyberb May 14, 2026
b569243
games.cli: full server/games subcommands, drop REST Basic-Auth path
cyberb May 14, 2026
0834abd
steamcmd: drop the LD_LIBRARY_PATH export and the test's runuser dance
cyberb May 14, 2026
c3a9481
steamcmd: revert pre-bootstrap, restore runtime-copy in wrapper
cyberb May 14, 2026
c7fe45e
steamcmd: handle exit 42 (self-update relaunch) like Valve's steamcmd.sh
cyberb May 15, 2026
6f50123
test: import cli helper via package path (matches bitwarden's from te…
cyberb May 15, 2026
44fca0d
steamcmd: seed runtime in install/refresh hook, wrapper is env+exec only
cyberb May 15, 2026
8d3b21c
test/cli: use /snap/bin/games.cli full path
cyberb May 15, 2026
6366717
test: use /snap/bin/games.cli everywhere, not only in helper
cyberb May 15, 2026
3ab83df
test: escape $? so remote shell evaluates the exit code
cyberb May 16, 2026
ba51a74
backend/db: enable WAL + busy_timeout to fix SQLITE_BUSY under concur…
cyberb May 16, 2026
99ba22c
test: drop vestigial test_steamcmd_diagnostics
cyberb May 16, 2026
a20020a
ci: flatten playwright artifacts into per-project screenshots/ + videos/
cyberb May 16, 2026
6223b2c
test: drop extra 'log/' subdir under artifact/<distro>/
cyberb May 16, 2026
17fa9f5
e2e: always record video for the install spec
cyberb May 16, 2026
8f9d274
e2e: write shoot() screenshots to disk, not html-report attachments
cyberb May 16, 2026
6688767
e2e: drop fullPage in shoot() so fixed bottom-nav anchors correctly
cyberb May 16, 2026
b5ccfb7
css: use 100dvh + larger bottom padding so mobile autohide-bar doesn'…
cyberb May 16, 2026
b0b800b
ui: sticky bottom-nav + settings polish + steam stub state
cyberb May 16, 2026
da2f0b3
css: restore scroll-padding/margin-bottom for sticky-nav mid-scroll o…
cyberb May 17, 2026
f0ce91b
auth: backend OIDC over authelia.socket, drop syncloud-CA trust
cyberb May 17, 2026
1211257
catalog: convert init() to Start() called from main
cyberb May 17, 2026
1cc5334
catalog: generate Steam entries from LinuxGSM at build time
cyberb May 17, 2026
a296228
ci: disable pipeline on pull_request events, push-only for now
cyberb May 17, 2026
8e7c289
installer/ui: treat source=linuxgsm as Steam path
cyberb May 17, 2026
07d05bd
backend: untrack built binary, add .gitignore
cyberb May 17, 2026
e873ee5
backend/installer: extract SteamInstaller + EggInstaller, inject from…
cyberb May 17, 2026
a67e50e
db: own all SQL, expose typed methods, ctor + Start lifecycle
cyberb May 17, 2026
37fc7c0
catalog+installer: recipe-driven installs, drop bash egg path
cyberb May 17, 2026
bee2862
installer/recipe: resolve nested binary path after extract
cyberb May 17, 2026
eafadd9
auth: forward proto/host headers on unix-socket calls to Authelia
cyberb May 17, 2026
5652ca4
catalog/convert: drop games with no install recipe instead of marking…
cyberb May 17, 2026
b3530ad
catalog/overrides: teeworlds tier=compatible to match e2e expectations
cyberb May 18, 2026
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
106 changes: 80 additions & 26 deletions .drone.jsonnet
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
local name = 'game-server';
local go = '1.23';
local name = 'games';
local go = '1.25';
local nginx = '1.24.0';
local node = '20';
local platform = '26.04.7';
local platform = '26.04.10';
local python = '3.12-slim-bookworm';
local deployer = 'https://github.com/syncloud/store/releases/download/4/syncloud-release';
local distros = ['bookworm', 'buster'];
local distro_default = 'bookworm';
local arch = 'amd64';

local platform_image(distro, arch) =
'syncloud/platform-' + distro + '-' + arch + ':' + platform;

[{
kind: 'pipeline',
type: 'docker',
Expand All @@ -32,20 +35,58 @@ local arch = 'amd64';
'./nginx/build.sh',
],
},
] + [
{
name: 'nginx test',
image: 'syncloud/platform-' + distro_default + '-' + arch + ':' + platform,
commands: [
'./nginx/test.sh',
],
},
name: 'nginx test ' + distro,
image: platform_image(distro, arch),
commands: ['./nginx/test.sh'],
}
for distro in distros
] + [
{
name: 'web',
image: 'node:' + node,
commands: [
'./web/build.sh',
],
},
{
name: 'catalog',
image: 'golang:' + go,
commands: [
'./catalog/build.sh',
],
},
{
name: 'jre',
image: 'debian:bookworm-slim',
commands: [
'./jre/build.sh',
],
},
] + [
{
name: 'jre test ' + distro,
image: platform_image(distro, arch),
commands: ['./jre/test.sh'],
}
for distro in distros
] + [
{
name: 'steamcmd',
image: 'debian:bookworm-slim',
commands: [
'./steamcmd/build.sh',
],
},
] + [
{
name: 'steamcmd test ' + distro,
image: platform_image(distro, arch),
commands: ['./steamcmd/test.sh'],
}
for distro in distros
] + [
{
name: 'backend',
image: 'golang:' + go,
Expand All @@ -57,15 +98,17 @@ local arch = 'amd64';
name: 'cli',
image: 'golang:' + go,
commands: [
'cd cli',
'mkdir -p ../build/snap/meta/hooks',
'CGO_ENABLED=0 go build -buildvcs=false -o ../build/snap/meta/hooks/install ./cmd/install',
'CGO_ENABLED=0 go build -buildvcs=false -o ../build/snap/meta/hooks/configure ./cmd/configure',
'CGO_ENABLED=0 go build -buildvcs=false -o ../build/snap/meta/hooks/pre-refresh ./cmd/pre-refresh',
'CGO_ENABLED=0 go build -buildvcs=false -o ../build/snap/meta/hooks/post-refresh ./cmd/post-refresh',
'CGO_ENABLED=0 go build -buildvcs=false -o ../build/snap/bin/cli ./cmd/cli',
'./cli/build.sh',
],
},
] + [
{
name: 'cli test ' + distro,
image: platform_image(distro, arch),
commands: ['./cli/test.sh'],
}
for distro in distros
] + [
{
name: 'package',
image: 'debian:bookworm-slim',
Expand All @@ -76,20 +119,32 @@ local arch = 'amd64';
},
] + [
{
name: 'test ' + distro,
name: 'test ' + distro_default,
image: 'python:' + python,
commands: [
'DOMAIN="' + distro + '.com"',
'APP_DOMAIN="' + name + '.' + distro + '.com"',
'DOMAIN="' + distro_default + '.com"',
'APP_DOMAIN="' + name + '.' + distro_default + '.com"',
'getent hosts $APP_DOMAIN | sed "s/$APP_DOMAIN/auth.$DOMAIN/g" | tee -a /etc/hosts',
'cat /etc/hosts',
'APP_ARCHIVE_PATH=$(realpath $(cat package.name))',
'cd test',
'./deps.sh',
'py.test -x -s test.py --distro=' + distro + ' --app-archive-path=$APP_ARCHIVE_PATH --app=' + name + ' --arch=' + arch,
'py.test -x -s test.py --distro=' + distro_default + ' --app-archive-path=$APP_ARCHIVE_PATH --app=' + name + ' --arch=' + arch,
],
},
] + [
{
name: 'test-ui-' + projectName,
image: 'mcr.microsoft.com/playwright:v1.59.1-jammy',
commands: [
'DOMAIN="' + distro_default + '.com"',
'APP_DOMAIN="' + name + '.' + distro_default + '.com"',
'getent hosts $APP_DOMAIN | sed "s/$APP_DOMAIN/auth.$DOMAIN/g" | tee -a /etc/hosts',
'cat /etc/hosts',
'PLAYWRIGHT_DOMAIN=' + distro_default + '.com ./ci/ui.sh ' + projectName,
],
}
for distro in distros
for projectName in ['desktop', 'mobile']
] + [
{
name: 'upload',
Expand Down Expand Up @@ -150,19 +205,18 @@ local arch = 'amd64';
},
],
trigger: {
event: ['push', 'pull_request'],
event: ['push'],
},
services: [
{
name: name + '.' + distro + '.com',
image: 'syncloud/platform-' + distro + '-' + arch + ':' + platform,
name: name + '.' + distro_default + '.com',
image: platform_image(distro_default, arch),
privileged: true,
volumes: [
{ name: 'dbus', path: '/var/run/dbus' },
{ name: 'dev', path: '/dev' },
],
}
for distro in distros
},
],
volumes: [
{ name: 'dbus', host: { path: '/var/run/dbus' } },
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ node_modules/
web/dist/
*.snap
.idea/
catalog/work/
# backend/catalog/catalog.json is committed as a stub so 'go build' works
# locally without running catalog/build.sh; CI regenerates it.
.claude/
135 changes: 135 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# CI

http://ci.syncloud.org:8080/syncloud/games (via 192.168.1.101:8080).

Check builds via API:
```
curl -s "http://192.168.1.101:8080/api/repos/syncloud/games/builds?limit=5"
```

Check which step failed:
```
curl -s "http://192.168.1.101:8080/api/repos/syncloud/games/builds/{n}" | python3 -c "import json,sys; d=json.load(sys.stdin); [print(s['name'], s['status']) for st in d['stages'] for s in st['steps']]"
```

Tail a specific step (stage_number/step_number, both 1-indexed):
```
curl -s "http://192.168.1.101:8080/api/repos/syncloud/games/builds/{n}/logs/1/{step}" | python3 -c "import json,sys; [print(l.get('out','').rstrip()) for l in json.load(sys.stdin)]"
```

Artifacts at `http://ci.syncloud.org:8081/files/games/{build}-amd64/`.

# Status

WIP on `wip` branch. Issue: syncloud/platform#35.

Last green: build #26 (lib64 bundle landed), build #27 has steamcmd diagnostics.

Phases shipped:
- 0: snap skeleton, stub catalog API, store-styled Vue UI
- 1: server CRUD + SQLite (modernc.org/sqlite)
- 2: process management (start/stop/restart, SIGTERM+10s+SIGKILL, process-group)
- 3: SteamCMD vendor (amd64 only — 32-bit binary, anonymous + user/pass logins)
- 3c: amd64 lib bundle for 64-bit games (CS2/Valheim/Rust/Factorio) — snap is now host-lib-independent for both archs
- 4: Pelican egg consumer (best-effort non-docker, parses parkervcp/eggs format)
- 4b: real Teeworlds install + start + UDP-bound probe — proves the integration test really plays a game in CI
- 5: in-memory ring-buffer log endpoint (500 lines / server)
- 6: A2S_INFO Source-engine UDP server query (with challenge handshake)
- 7: OIDC client registration via `platformClient.RegisterOIDCClient`
- 8: Playwright e2e (desktop + mobile)
- 9: docs
- 16: mobile bottom-bar nav
- 17: minecraft real install (Pelican egg + bundled JRE)
- 18: real OIDC code+PKCE flow + backend session middleware; nginx forward-auth dropped
- 19: full minecraft cycle (install → EULA → start → tcp-bind), SVG icons extracted to assets, dead authelia templates removed

In progress / open:
- 3b: real HLDS (CS 1.6, appid 90, 250MB) install via SteamCMD — xfailed.
steamcmd bootstrap fails with "Steam needs to be online to update" + empty
Steam/logs/. lib32 + writable runtime dir aren't enough. Diagnostics added
in test_steamcmd_diagnostics — read CI build log to root-cause.

# Architecture

- `cli/` — Go cobra: install / configure / pre-refresh / post-refresh / cli (storage-change, access-change, backup-pre-stop, restore-pre-start, restore-post-start)
- `backend/` — Go HTTP server on `unix:/var/snap/games/current/backend.sock`
- `db/` — SQLite open + schema
- `server/` — Store with CRUD on servers
- `runner/` — exec.Cmd-based process management with ring-buffer log capture
- `installer/` — SteamCMD + Pelican egg install logic
- `query/` — A2S_INFO UDP query
- `web/` — Vue 3 + Vite. Plain CSS theme cribbed from `../store/web` (light/dark, no Element Plus). `web/e2e/` is a self-contained Playwright TS package.
- `config/` — `nginx.conf` (no auth_request — backend session middleware enforces) + `proxy.conf`. `{{ .AuthUrl }}` rendered by `config.Generate`.
- `nginx/` — vendored nginx (build.sh copies the entire FS from the nginx docker image)
- `steamcmd/` — `build.sh` downloads steamcmd_linux.tar.gz
- `test/` — pytest integration tests using `syncloud-lib`

# Constraints

- **amd64 only.** `.drone.jsonnet` lists only amd64. SteamCMD ships x86_64.
- **SteamCMD is 32-bit i386.** Snap will need 32-bit glibc bundled — first SteamCMD-based test installs may fail until that's added. Tracked as a follow-up.
- **Pelican eggs that need Docker won't work.** Backend runs install scripts directly. Best-effort for bash/native eggs (Teeworlds, Minetest work).
- **Auth = OIDC code+PKCE against Authelia + signed session cookie.** Backend's `auth.Middleware` checks the cookie on every `/api/*` request on the HTTP socket; nginx no longer does `auth_request`. Integration tests use a separate `cli.sock` (file-mode 0660, no auth middleware) reached via `/snap/bin/games.cli`.
- **Backend ↔ Authelia goes over `authelia.socket`, not HTTPS.** Discovery / token / JWKS requests dial `/var/snap/platform/current/authelia.socket` (path from `golib`'s `GetAuthLocalSocket()`, stored as `authSocket` in `oidc.json`). A RoundTripper rewrites the public `https://` URLs from the discovery doc to `http://` before dialing. The browser redirect (`AuthCodeURL`) still uses the public HTTPS URL because the browser can't dial a unix socket. No syncloud-CA trust needed in the snap as a result.

# Integration test fixture

Use **teeworlds** for any test that needs a real install — smallest server in parkervcp/eggs (~10MB binary, headless, A2S-queryable). Egg: `https://raw.githubusercontent.com/parkervcp/eggs/master/game_eggs/teeworlds/egg-teeworlds.json`. Anonymous-friendly Steam apps (cs2, tf2, gmod, valheim, zomboid, ark) work for Steam-path tests.

# Storage layout (on device)

```
/snap/games/current/ # read-only squashfs
steamcmd/ # bundled steamcmd_linux.tar.gz contents
linux32/steamcmd # i386 bootstrap binary
steamcmd.sh, steam.sh # original wrapper (unused)
lib32/ # ~40MB. i386 base runtime:
# ld-linux.so.2
# libc.so.6, libstdc++.so.6, libgcc_s.so.1
# libcurl.so.4, libssl.so.3, libsdl2, libgl1, ...
lib64/ # ~25MB. amd64 base runtime:
# ld-linux-x86-64.so.2
# same lib set, amd64 variants
web/dist/ # Vue SPA build
nginx/ # vendored nginx (etc/, opt/, usr/, lib/)
bin/
cli # Go cobra hooks binary
backend # Go HTTP backend (static)
service.backend.sh, service.nginx.sh # systemd wrappers
steamcmd.sh # wrapper that invokes linux32/steamcmd
# via lib32/ld-linux.so.2 + lib32

/var/snap/games/current/ # writable, $SNAP_DATA
database.db # SQLite catalog of installed servers
backend.sock # nginx -> backend
servers/<name>/ # per-server install (game files)
config/ # rendered Authelia includes
oidc.secret # OIDC client_secret
nginx/ # nginx state (temp_path etc.)
.steam-home/ # steamcmd's $HOME — Steam/logs/, .steam/
.steam-runtime/ # steamcmd's writable copy
# (linux32 + public + package + steamcmd.sh)

/var/snap/games/common/ # shared across revisions, $SNAP_COMMON
web.socket # platform -> nginx (PLATFORM CONTRACT)
installed # marker file
```

`web.socket` must stay at `$SNAP_COMMON/web.socket` (platform contract). Everything else under `$SNAP_DATA` so refresh rollback works.

# Game launch wrappers

`installer.steamStartCmd` builds the startCmd for each Steam game using two helpers in `backend/installer/installer.go`:

- `wrapI386(binary, extraPaths, args)` — for HLDS, TF2, GMod (32-bit SrcDS):
```
LD_LIBRARY_PATH=lib32[:extra] lib32/ld-linux.so.2 --library-path lib32[:extra] $bin $args
```
- `wrapAmd64(binary, extraPaths, args)` — for CS2, Valheim, Rust (64-bit native):
```
LD_LIBRARY_PATH=lib64[:extra] lib64/ld-linux-x86-64.so.2 --library-path lib64[:extra] $bin $args
```

`extraPaths` typically includes `$installDir` and `$installDir/<mod>` so game-private engine libs (`libtier0_s.so`, `libsteam_api.so`, etc.) resolve.

This pattern means the snap never depends on host glibc/libstdc++/libGL state — same snap should run on any Linux host the platform supports.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# game-server
# games

Syncloud app: dedicated game server panel.

Expand All @@ -13,7 +13,7 @@ See commits on `wip` for the phased build-out (server CRUD → process managemen
## Architecture

- `cli/` — Go install/configure/access-change/storage-change/backup hooks (cobra).
- `backend/` — Go HTTP backend on `unix:/var/snap/game-server/current/backend.sock`.
- `backend/` — Go HTTP backend on `unix:/var/snap/games/current/backend.sock`.
- `web/` — Vue 3 + Vite SPA, store-styled (`../store/web` look). Plain CSS, no Element Plus.
- `config/` — nginx + authelia templates rendered at configure time.
- `nginx/` — vendored static nginx.
Expand Down
1 change: 1 addition & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/backend
Loading