Add the chassis libraries with a bearer presence check
Summary
This MR adds the chassis libraries under chassis/, following the design in docs/design/chassis-libraries.md, which is added here. docs/design/authn.md (from !195 (merged)) defines the full inbound-authentication design: the target state with the LabKit URT module, the interim Rails-issued JWT verifier, token exchange, and a development-mode stub that release builds leave out. This MR implements only the first piece of that design. The middleware checks that a bearer token (the JWT) is present, and it does not verify the token. Verification, token exchange, and development mode come in later MRs, once appconfig lands (#106).
Libraries
chassis/gois the Go modulegitlab.com/gitlab-org/lab-bench/bench/chassis/go.chassis/rustis thebench-chassiscrate. It is excluded from bench's Cargo workspace, socargo buildof bench never compiles it.- Each has an
authpackage/module with a middleware that answers 401 when theAuthorizationheader is absent, names a scheme other thanbearer(case-insensitive, per RFC 7235), or carries an empty token. Otherwise it passes the request on. It checks presence only, not validity. - Go:
auth.Middleware(next http.Handler) http.Handler. - Rust:
bench_chassis::auth::BearerAuthLayer, a tower Layer/Service pair in the style of labkit-rs's HTTP layers, so it can move into labkit-rs later.
How assemblies get them Generated assemblies import the libraries as ordinary dependencies. Bench never writes chassis sources into the adopter's tree.
- A release
bench(GoReleaser setsBENCH_VERSIONandBENCH_COMMIT={{ .FullCommit }}onvX.Y.Ztags) pins both chassis libraries to the commit its release tag points at. Go runsgo get .../chassis/go@<commit>beforego mod tidy, which puts a pseudo-version likev0.0.0-20261023081318-c50a3efb03e0in the adopter's committedgo.mod. Rust getsbench-chassis = { git = ".../bench.git", rev = "<commit>" }in the gitignored generated workspace. The release path only needs a pushed commit, so it can be tested from any pushed commit. Readable release tags are deferred; the decision is recorded on #110, and the draft is parked in the closed !216 (closed). - Any other
bench, such as a local build, reads them from the checkout it was compiled from, so it needs no push and sees uncommitted edits underchassis/. Go: bench copiesgo.modandgo.sumto a gitignored.bench/go.dev.modand.bench/go.dev.sum, adds areplaceonto the checkout, and runsgo mod tidyandgo buildwith-modfile, so the committedgo.modnever gets a local path. Rust: apathdependency in the generated workspace. - The
labbench_tools.goanchor blank-imports the auth package so tidy keeps the require.
Wiring
- Go
main.go.templateservesauth.Middleware(mux). Wrapping the whole mux means every route and every unmatched path is authenticated. Probes are served on the separate probe port. - Rust
main.rs.templateadds.layer(BearerAuthLayer::new())innermost, directly afterregister_services(). LabKit's access log, trace, correlation and metrics layers still record rejected requests, andRouter::layercovers the fallback, so unmatched paths get 401. - Both chassis log a startup warning: "inbound auth only checks that a bearer token is present; tokens are not verified".
- Both answer 401 with Go's
http.Errorresponse: atext/plainbody ofunauthorized, perdocs/design/http-adapter-contract.md.
CI and docs
- The
--releaseintegration jobs buildbenchwithBENCH_VERSIONandBENCH_COMMIT=$CI_COMMIT_SHA, so they exercise the release pin against the MR's pushed commit. The checkout path is covered by unit tests and local runs. - New jobs
test:chassis:go(gofmt, go vet, go test) andtest:chassis:rust(fmt, clippy-D warnings, nextest, cargo deny with the rootdeny.toml). Each runs only when its directory changes. AGENTS.mdlistschassis/and both gates;ARCHITECTURE.mddescribes the pin underbuild.README.mdnotes that acargo installbench is a dev build that reads the chassis from Cargo's checkout, and points adopters to the release install.authn.mdnow points the interim section at the chassis libraries, describes the Rust layer and the startup warning, and records that the planned development-mode stub (#111) ships in every build, including release builds, with the risk accepted for now. This is design only, and nothing in this MR implements the stub.
Testing
- Unit tests in each library cover absent,
Basic x,Bearer,Bearer, andBearer(no separator), all 401.Bearer xandbearer xpass, and an unmatched path gets 401. Go uses httptest with a real mux; Rust uses a real axum Router. - Bench unit tests cover the rendered templates, release and dev source selection, the dev modfile, and both Rust dependency forms; 331 pass.
tests/integration-go.shandtests/integration-rust.shnow send a token on every route and check that missing,Basic xandBearerget 401, that the 401 body isunauthorized, and thatbearer xpasses. Both pass locally against uncommitted checkout changes (Go ran against.bench/go.dev.modwith the committedgo.moduntouched; cargo builtbench-chassisfrom the checkout path), and both servers logged the warning.- The
--releasevariants (Docker) were not run locally.
Reviewer checklist
- Reviewed the changes.
- Change matches the described intent and stays in scope.
- Milestone and labels are applied.
- CI is green.
Related issue
Related to #87
Related to #110 (part B here; part A deferred, see the issue)