- Rust 97.3%
- Shell 2%
- Dockerfile 0.7%
| .github/workflows | ||
| ci | ||
| crates/gateway | ||
| policies | ||
| .dockerignore | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| clippy.toml | ||
| deny.toml | ||
| Dockerfile | ||
| justfile | ||
| justfile.ci | ||
| README.md | ||
| rust-toolchain.toml | ||
| rustfmt.toml | ||
alysia-gateway
The edge gateway of the Alysia platform, extracted from the
Alysia monorepo (services/gateway/).
Terminates TLS (mixed mTLS: socle services are named by their verified
client certificate, the cert-less WASM plugin falls through to its
bearer), authorizes every request against a versioned Cedar policy set
evaluated in process, and routes it: native routes (queue, transfers,
poll, aggregated ping) are served here, everything else is forwarded to
the socle service that owns it — the caller's bearer never travels
further. Serves /healthz in the clear (8081), the business routes
behind mixed mTLS (8443), and the same business routes in the clear for
the plugin (8082, ADR 0006).
Layout
| Path | Role |
|---|---|
crates/gateway/ |
The service crate (lib + binary + integration tests) |
policies/policies.cedar |
The versioned Cedar policy set, compiled at boot — moved from the monorepo's infra/gateway/policies.cedar, see below |
Dockerfile |
Single-binary image (alysia/gateway), built from this repo |
justfile.ci + ci/ |
Vendored from alysia-ci-templates at TEMPLATE_REV (see .github/workflows/ci.yml) — never patch locally |
The policies move
In the monorepo the policy set lived at infra/gateway/policies.cedar
while the code that compiles it (src/cedar.rs, src/lib.rs) and the
tests that pin it (tests/cedar.rs, nine permit) live in the service:
the file now lives in the repo that boots it, at
policies/policies.cedar, byte-identical apart from the header (which
records the provenance). Only the paths moved:
src/config.rs:DEFAULT_POLICY_PATHispolicies/policies.cedar(overridable per environment viaALYSIA_AUTHORIZATION_POLICY);src/cedar.rs+tests/{cedar,support}.rs: theversioned_path()reads../../policies/policies.cedarfrom the crate dir.
The monorepo keeps its own copy until the compose stack reads the policy
from here (or via ALYSIA_AUTHORIZATION_POLICY); the two files must stay
in sync until then.
The identity decoupling
In the monorepo the forwarded-login and permission-sync tests booted the
real identity service over containers (Postgres + JetStream) as an
alysia-identity dev-dependency. That coupled two release trains to
prove what the gateway owns: the request reconstruction (verb, natural
route, headers, verbatim body/query) and the refusal that never forwards.
This repo has no alysia-identity dependency; tests/support holds a
stub identity service (stub_identity: login + permissions snapshot,
behind the shared API version layer like the real one) and the TLS-shape
tests serve it behind a strict mTLS listener, so criterion 3 (the
gateway's own certificate completes the handshake) is still proved.
The contract with the real service is consumer-driven and compile-time:
the stub answers the very PlayerLoginResponse / PermissionsSnapshot
types of alysia-proto, and the tests deserialize the gateway's answer
into those same types — a drift of the real shape fails here. Bonus: no
test needs a container runtime anymore.
Dependencies
alysia-* crates come from the versioned libs release train as exact-tag
git dependencies — never a branch, never a vendored copy. All alysia-*
deps move together on a single tag (lockstep releases, currently
libs-v0.1.0):
alysia-service = { git = "https://git.zeto.fr/alysia/alysia-libs.git", tag = "libs-v0.1.0" }
Development
just ci-lint # fmt + clippy + machete + deny
just --set test_args "" ci-test # full suite (unit + integration, all in-process)
just --set image "alysia/gateway" ci-build # local image build (tag `local`); CI pushes `alysia/gateway:<sha>` on main
No DOCKER_HOST, no .sqlx/: the gateway holds no database and every
test is in-process.
Image push
ci-build produces alysia/gateway:local. CI pushes
git.zeto.fr/alysia/alysia-gateway/gateway:<sha> on main/tags — but only
once a REGISTRY_TOKEN secret exists on this repo (it does not yet; the
push step skips loudly until then). No image is ever pushed by hand.