Take the link from wg-app-link instead of keeping a second copy

The five modules underneath this backend that were never about AI
sessions -- the pinned CA and leaf, QR enrollment and the bearer token,
wg0 binding and the certificate's SANs, owner-only files, and the RON
house rules -- were written twice, once here and once in dev-updater,
and had drifted. They now come from the submodule, as a path dependency
so both projects stay locked to one commit.

What stayed is what makes this project itself: the routes, the drivers,
the config schema, and the auth middleware, which is generic over this
server's state. Sharing a transport is worth doing; sharing an API would
mean inventing a vocabulary neither project wants.

Four dependencies go with the code -- rcgen, qrcode, subtle and if-addrs
are no longer named here at all -- and the three that remain are now
described by what still uses them rather than by what used to.

Verified by running it, not only by building: a fresh server generates
its CA, prints an `aiapp://enroll` QR with the scheme now passed as a
parameter, covers 127.0.0.1, 10.0.2.2 and wg0's 10.66.0.1 in the leaf,
answers an enrolled token and returns 401 without one, and writes
config.ron in the house rules with every file owner-only. 36 tests pass,
clippy is silent, rustfmt is clean.
This commit is contained in:
iris committed 2026-08-28 17:14:33 -04:00
1 parent a83dbcff6a
commit aa05ff9336
13 files changed
+76 -526

No files matched your search

+21 -7
View File
@@ -39,7 +39,7 @@ repo is in PLAN.md's "Backend layout" section.
- `server/` — Rust backend (`ai-server`). `main.rs` bootstraps (TLS, the
auth layer, token/QR enrollment, wg0 binding), `routes.rs` has the HTTP
table in its module doc comment, `auth.rs` the bearer-token middleware,
`config.rs` the persisted schema and the RON its file is written in,
`config.rs` the persisted schema (written in the shared RON house rules),
`session/` the manager (registry pattern), `Driver` trait + event model,
`EchoDriver`, and transcripts.
- `app/` — Compose Android app, single `:androidApp` module, package
@@ -52,11 +52,24 @@ repo is in PLAN.md's "Backend layout" section.
`server/service`) and then the APK (built in `app/`), in that order. The
project it serves is the repository, not either half of it, which is why
this sits at the root rather than in `app/`.
- `server/src/certs.rs` — the TLS certificates, generated in process on
first start into `$XDG_CONFIG_HOME/ai-app/certs`: idempotent CA, leaf
reissued every start covering every local IPv4 plus 127.0.0.1 and
10.0.2.2 (emulator → host). Regenerating the CA strands the installed
app — the one-way door.
- `wg-app-link/` — a **git submodule**, and the half of this backend that
dev-updater also needed: the pinned CA and leaf (`certs`), QR enrollment
and the bearer token (`enroll`), wg0 binding and the certificate's SANs
(`netif`), owner-only files (`private`), and the RON house rules
(`format`). Both projects had written all five, and they had drifted;
see that repo's `README.md` for the diff that decided each one and the
permissions bug the extraction found. Clone with
`git clone --recurse-submodules`, or `git submodule update --init` in an
existing checkout — `server/` will not build without it, since it is a
path dependency rather than a registry one, which is what keeps the two
projects version-locked to the commit this repo pins.
The certificates are still the one-way door: the CA is generated once on
first start into `$XDG_CONFIG_HOME/ai-app/certs` and regenerating it
strands the installed app.
What deliberately did **not** move is the API surface and the config
*schema* — routes, drivers, sessions and setups are what makes this
project itself, and a shared vocabulary for them would be inventing one
neither project wants.
## Status
@@ -129,7 +142,8 @@ mangles an argument.
## Checking your work
- Server: from `server/`, `./run-tests.sh` (or `cargo test`) +
- Server: `./run-tests.sh` from the repo root (or `cargo test` from
`server/`) +
`cargo clippy --all-targets` + `cargo fmt`. The build stays
warning-clean and rustfmt-clean at the defaults — there is no
`rustfmt.toml` and there should not be one.