Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ad845d9
Add opt-in Sector Alpha agent and bounded public queries
cosmosquark Oct 13, 2026
0eacc34
Support independent capability credential rotation
cosmosquark Oct 13, 2026
59a513c
Keep agent reporting alive through lifecycle lock contention
cosmosquark Oct 14, 2026
a42a6f9
Guide agent enrollment and bind all owned local servers
cosmosquark Oct 15, 2026
76a284e
Validate hostname publication against local machine addresses
cosmosquark Oct 15, 2026
ff0e704
Verify separate game subdomains on one machine
cosmosquark Oct 15, 2026
fea4dfc
Document same-machine subdomain setup step by step
cosmosquark Oct 15, 2026
7012e53
Route all official agent traffic through the game-server API
cosmosquark Oct 15, 2026
cd8fd03
Report approved player connection ports separately from query ports
cosmosquark Oct 15, 2026
a6ce197
Do not infer player listeners from administration or query-only ports
cosmosquark Oct 15, 2026
ae31a67
Add skippable first-run setup tour
cosmosquark Oct 16, 2026
175dbaa
Group Sector Alpha changelog notes with the Workshop history
cosmosquark Oct 17, 2026
4474aed
Separate website onboarding from game-server execution API
cosmosquark Oct 18, 2026
aa8e29e
Add TeamSpeak MariaDB mode and the alphagsm-api origin.
cosmosquark Oct 18, 2026
02ab9ef
Query anonymous status protocols locally and prove TeamSpeak names.
cosmosquark Oct 19, 2026
de3de19
Keep one outbound WebSocket for Sector Alpha presence and job wakes.
cosmosquark Oct 19, 2026
e1c6651
Add a TeamSpeak detail query for channel order and voice clients.
cosmosquark Oct 19, 2026
a2dea2a
Enroll managed servers on the default API origin.
cosmosquark Oct 20, 2026
eb5e078
Merge remote-tracking branch 'origin/master' into codex/sector-alpha-…
cosmosquark Nov 4, 2026
d1c49fb
Add an optional Linux user service for the Sector Alpha agent.
cosmosquark Nov 4, 2026
e00ce51
Install the AlphaGSM agent service for the user or the system.
cosmosquark Nov 4, 2026
e52e44b
Document the agent service and keep Windows commands free of Linux mo…
cosmosquark Nov 5, 2026
7dc2918
Resolve the ET: Legacy Linux archive from the current download page.
cosmosquark Nov 5, 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
174 changes: 174 additions & 0 deletions DEVELOPERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,42 @@ AlphaGSM is a Python CLI that normalises game-server lifecycle management across
- a runtime layer that can launch either local screen-backed processes or Docker containers
- dedicated test layers for unit, integration, and streamed smoke coverage

## First-run guidance

`core.main` routes only bare invocation, `--welcome` and `--skip-welcome` to
`core.welcome`. Automatic prompting requires both stdin and stdout to be TTYs
and no acknowledgement marker. All named server/agent commands, internal workers,
help and version follow their usual paths. Keep this boundary so automation
never blocks on first-run questions.

The tour passes argv arrays back through ordinary dispatch after previews and
explicit approvals. It resolves game aliases through `MODULE_CATALOG`, restricts
local names, and rejects `core.server_names.RESERVED_SERVER_NAMES`, numeric selectors
and `all` before dispatch. Never let wildcard/count interpretation bypass the
existing-record check. Creation checks `lexists` before the preview and again
under the ordinary per-record state lock, refusing existing files or links.
Setup has separate approval; games never start from the tour. Optional agent
setup has a separate network confirmation and keeps its own enrollment/binding
permissions; the tour does not call capability-enable commands.

`core.welcome_state` owns the non-secret, versioned `welcome-v1.done` marker under
configured `core.alphagsm_path`. Creation is exclusive, mode 0600, with no-follow
where available, ownership checks and no overwrite of existing markers. It
preserves existing directory permissions and keeps acknowledgement separate from
server/agent configuration and all consent. EOF/Ctrl+C stops further commands;
completed approved actions are not rolled back.

Run the isolated first-run smoke checks with:

```sh
PYTHON_BIN=python3 bash tests/smoke_tests/run_first_run_tour.sh
```

This covers unit boundaries plus actual CLI subprocesses and POSIX PTYs against
disposable config/home paths, including the `all` overwrite regression. PTY cases
require POSIX and skip on platforms without PTYs. It neither downloads game
assets nor starts servers, and does not establish game lifecycle support.

## Documentation Split

Keep repository docs split by audience and preferred operator path:
Expand Down Expand Up @@ -1183,6 +1219,144 @@ When upgrading an existing source environment that installed the obsolete
AlphaGSM uses the `python-crontab` distribution's `CronTab` API. A fresh binary or
fresh environment does not need this cleanup.

## Sector Alpha outbound agent and shared public queries

`agent.contracts` is the dependency-free closed version-one wire schema.
`server.public_query` contains the immutable public A2S_INFO/Java SLP registry,
uses bounded parsers in `utils.query`, and never constructs Server or falls back
to console/RCON/HTTP/TCP health. Central consumers must pin a reviewed commit
and exclude their own infrastructure before numeric connect.

The optional `agent` package keeps scoped credentials and consent under a
private POSIX directory outside game datastores. Policy and report credentials
are independent. The foreground manager opens one outbound WebSocket for
presence and job wakes, and falls back to HTTPS long polling when the socket
cannot open. It rechecks exact local bindings and policy under the normal CLI
lock, obtains final online authorization and persists executing before lifecycle
effects. A socket frame never skips those checks. Results are posted over HTTPS.
Outbound HTTPS and the agent WebSocket use a verified client context with a
minimum of TLS 1.2.
`alphagsm agent run` starts the foreground agent and does not install a
service. `alphagsm agent install-service` writes `alphagsm.service` for the
current user, enables it, and starts it. `install-service --system` writes
the same unit under `/etc/systemd/system`, enables it for boot, and starts
it as one operator account, never as root. Both execute the invoked program
with `agent run`. There is no separate alphagsm-agent program. The Linux
account lookup is imported only for a system install, so Windows commands do
not load `grp` or `pwd`. Neither command changes reporting, management,
publication or credentials. `uninstall-service` disables, stops and removes
the selected unit and leaves the enrollment in place. The tour and game
setup do not install it.
`Journal` stores durable results until acknowledgement; interrupted execution
reconciles unknown and never repeats effects. A global foreground-service lock
prevents competing pollers. No secrets are accepted as CLI arguments.

The official provider is `https://alphagsm-api.sector-alpha.net` for every
agent operation: enrollment redemption, binding registration, ownership-challenge
minting, POST stats, and the outbound execution protocol (policy acknowledgement,
the agent session socket, command polling, final authorization and results).
The agent does not ask which host to use. Sector Alpha verifies a challenge by
querying the server. Owners queue commands and view data on the website.
`Transport` sends every approved route to the one configured origin. It retains
one canonical API provider origin in local configuration, without redirects or
endpoint discovery. No new persisted secret/origin fields are introduced.

`canonical_agent_origin()` still maps exact official HTTPS website/API authorities
(default/443 port, case and root-slash variants) to the canonical API provider
origin. `Config.load()` and the next ordinary write retain this normalization,
preserving IDs, keys, bindings and permissions. Explicit custom origins, lookalikes
and non-default ports keep the exact configured single origin for every agent path.
Restart foreground/user services after upgrading. The website still accepts
enrollment and binding registration from older clients.
The generic origin syntax validator still requires HTTPS roots and normalizes an
optional trailing slash. `agent.inventory` reads
only owned current-user JSON datastores without constructing Server (which can
migrate secrets or save runtime metadata). It exports an allowlist of module,
query port, primary player port, name, capacity and networking hints. `agent.network` accepts only globally
routable numerical suggestions, uses bounded TLS for its fixed address lookup,
and sends no agent credentials. Explicit `--host` bypasses discovery.

`agent bind TAG`, `agent bind '*'` and `agent setup` preview and confirm exact
bindings before registration or config writes. The portal's authenticated
`POST /v1/agent/bindings` accepts only a selected enrolled scope and SHA256 of the
local tag; it derives installation ownership from that scoped credential and
returns an idempotent binding ID/epoch. Registration sends only the tag reference;
later reports contain approved display metadata, whose name may match the tag.
Datastore secrets stay local. Registration grants no actions or publication. Existing
bindings retain their approved values on repeat runs; capabilities require
separate local enablement. Games outside the public query registry remain private.

Version-one report metadata has optional `connect_port`: a strict integer from
1 through 65535 or null. Existing required `port` remains the query port; unknown
metadata fields still fail validation. Missing `connect_port` remains valid for
legacy reports/configurations. Omission preserves the receiver's existing player
port; explicit null clears it.
Both presence and value participate in the final publication approval check.
Inventory infers it from the primary local `port`, independently of `queryport`;
guided and explicit binding approve it for every
canonical game. `--connect-port` overrides the advertised player port, while a
Minecraft `--port` override sets both unless the player override is explicit.
The final guided preview shows host/IP and both ports before saving. Existing
bindings acquire the field only through rebinding; runtime metadata refresh
never infers or changes either approved port. Registration remains scope/ref
only, and endpoint metadata uses the opted-in report channel. This does not add
public query profiles, client launch schemes or Steam client IDs.
Deploy the receiver's updated shared contract before clients create/rebind
servers with this field; old closed-schema receivers reject it. Existing saved
bindings keep omitting it until a confirmed rebind, preserving their wire format.

Hostnames are scoped to bindings, not installations or numerical machine IPs.
Different game tags may advertise different subdomains that resolve to the same
IP; each retains its own game profile, player port, query port, expected-IP policy,
publication consent and central ownership challenge. Single-server rebinding
does not mutate siblings, and wildcard endpoint prompts preserve per-server
hostnames on repeat runs. The agent neither provisions DNS nor routes traffic
between processes; a hostname alone cannot multiplex a shared numerical port.

`agent.preflight` applies hostname checks to copied public report items immediately
before transport. Optional per-binding `expected_public_ips` is local policy only;
it never enters metadata, registration or wire schemas. Automatic expectations
read allowlisted local network hints and use one route/IP lookup per batch. Fresh
complete A/AAAA answers must all be global and match expected machine addresses.
`agent.dns_lookup` uses pinned dnspython async resolution with absolute lifetimes,
an eight-worker bound and a 30-second batch ceiling. Timeout or mismatch changes
only the outgoing publication flag; later repair can restore publication without
rewriting consent. Numeric/private reports keep their existing behavior.

After DNS, the service rechecks current publication, endpoint, expected IPs and
provider relationship under the config lock, then sends with the current reporting
key before releasing the lock. Report POSTs have a hard ten-second HTTPS budget,
including DNS, TLS, headers and body. Expiry closes active sockets; a stalled system
resolver cannot later connect or accumulate additional workers. A service instance
retains its initial origin/installation relationship and must restart after local
re-enrollment before sending any new relationship's credentials.

The explicit `check-endpoint` diagnostic additionally probes only pinned matched
addresses through the immutable native registry, retaining the original SLP
virtual host and sharing a five-second protocol budget. It does not run as a
publication renewal hook, avoiding NAT-loopback failures turning into publication
flapping. Neither local check grants central endpoint verification. Standalone
builds collect `dns` dynamic protocol modules as well as the agent package.

Trusted local runtime helpers run in separate process groups with bounded
state/operation deadlines. `held_descriptor`/`inherited_state_lock` hand the
existing datastore sidecar lock to the child after an inode check. The helper
marks the descriptor non-inheritable for further command children and never
unlocks the shared open-file description; the parent retains exclusion until
it receives a result or kills the timed-out helper group. Unknown may reflect
an effect already applied by an independent game/Docker daemon.

Run `tests/smoke_tests/run_sector_alpha_agent.sh`, the agent/public-query unit
sets, and `ALPHAGSM_VALIDATE_AGENT=1` with Minecraft integration for each runtime.
Windows credential storage deliberately fails closed pending an ACL adapter.
Binary package collection, lint and coverage include agent. The service lives
in the separate alpha-platform-lite repository; it supplies PostgreSQL roles,
TLS transport round trips and worker isolation validation.

Credential generation is the management dispatch fence. Reporting authentication
uses its independent active key, so management key rotation cannot interrupt
reports. Local key replacement requires the previously enrolled capability and
never changes bindings/opt-ins; management generations must strictly advance.

## Game-specific BYO file contracts

Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ local-test:

coverage:
PYTHONPATH=.:src $(PYTHON_BIN) -m pytest tests/unit_tests \
--cov=agent \
--cov=core \
--cov=downloader \
--cov=downloadermodules \
Expand Down
67 changes: 67 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ The everyday flow is always the same:
Then `stop`, `backup`, or `update` as needed. Pick a game from
[the server guides](docs/README.md) if you want the exact module name.

After installation, run `./alphagsm` in a terminal for an optional setup tour.
Press Enter to skip, use `./alphagsm --welcome` to replay, or
`./alphagsm --skip-welcome` to skip from a script. The tour can help create a
local server and show everyday commands. Downloads need a separate confirmation.
Sector Alpha enrollment is optional and reporting/management stay off unless
you enable them separately. See [First-run setup](docs/first-run-setup.md).

For supported Steam-owned files, log in with `./alphagsm steam-auth login owned <username>`,
then run `./alphagsm myserver setup --auth-profile owned`. Setup remembers that
profile name. `--steam-dir /path/to/SteamLibrary/steamapps` uses installed files
Expand Down Expand Up @@ -553,3 +560,63 @@ Use:
- License: GPL v3.0, see [LICENSE](LICENSE)
- Credits: see [CREDITS](CREDITS)
- Changelog: [changelog.txt](changelog.txt)

## Optional Sector Alpha connection

AlphaGSM can connect to a compatible Sector Alpha service over outbound HTTPS.
Reporting and remote management are separate opt-ins and stay disabled until
you enable them locally. You choose each published server and which of status,
start, stop and restart it permits. Local AlphaGSM works without a connection.

```sh
alphagsm agent enroll
alphagsm agent bind '*'
```

The agent uses `https://alphagsm-api.sector-alpha.net` for every operation.
Another provider is used only with `--origin`. `alphagsm agent enroll` turns
reporting on and leaves management off. `alphagsm agent run` runs the agent
in the foreground. On Linux, `alphagsm agent install-service` enables and
starts a user service for that command so it keeps running after you close
the terminal. `install-service --system` enables and starts the same command
as a system service for your account, not as root. Neither changes reporting
or management. `alphagsm agent uninstall-service` disables and removes the
selected service and leaves the local enrollment in place. Custom providers
keep their configured origin.

The quoted `'*'` binds all
eligible local servers, inferring their settings and registering website IDs
automatically. Use `agent bind my-minecraft` for one server. Review the suggested
public address, player port, query port, publication and remote actions before saving.
The player port comes from the local game's main port; `--port` overrides the
query port and `--connect-port` overrides the player port for NAT. For Minecraft,
`--port` sets both unless `--connect-port` is also supplied. Existing bindings
keep their saved metadata until you rebind and approve a player port. Binding
does not enable reporting; approved endpoints are sent only in reports.
Update the receiving service before creating or rebinding servers: older
receivers reject the new player-port field. Existing saved bindings remain
compatible until you approve the field through rebinding.

Use `--host game.mygameserver.com` for an existing hostname. Public reports check
that all its DNS addresses match this machine's expected public IPs; `--public-ip`
provides an explicit override. `agent check-endpoint my-minecraft` tests the
advertised query port separately.

Multiple games can share one machine and public IP with separate subdomains:

```sh
alphagsm agent bind my-minecraft --host minecraft.mygameserver.com
alphagsm agent bind my-tf2 --host tf2.mygameserver.com
```

Each keeps its own player/query ports and permissions. Bulk binding also accepts
a different hostname at each server's endpoint prompt.
Follow the [step-by-step subdomain setup](docs/sector-alpha-agent.md#multiple-game-subdomains-on-one-machine)
for DNS records, NAT overrides, port checks and publication.

See [the connection guide](docs/sector-alpha-agent.md). The open source project’s
home is https://alphagsm.sector-alpha.net/; the gaming community and server
directory belong on https://sector-alpha.net/.

Use the owner dashboard and `alphagsm agent replace-credential reporting` or
`management` for independent key rotation; enter secrets only at hidden prompts.
4 changes: 4 additions & 0 deletions alphagsm
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ if sys.argv[1:2] == ["--_download"]:
from downloader import run_download_helper
sys.exit(run_download_helper(sys.argv[2:]))

if sys.argv[1:2] == ["--_agent-runtime"]:
from agent.runtime_helper import main
sys.exit(main(sys.argv[2:]))

import core as core # pylint: disable=wrong-import-position

if len(sys.argv) >= 5 and sys.argv[1] == "--_run-command":
Expand Down
Loading
Loading