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/go is the Go module gitlab.com/gitlab-org/lab-bench/bench/chassis/go.
  • chassis/rust is the bench-chassis crate. It is excluded from bench's Cargo workspace, so cargo build of bench never compiles it.
  • Each has an auth package/module with a middleware that answers 401 when the Authorization header is absent, names a scheme other than bearer (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 sets BENCH_VERSION and BENCH_COMMIT={{ .FullCommit }} on vX.Y.Z tags) pins both chassis libraries to the commit its release tag points at. Go runs go get .../chassis/go@<commit> before go mod tidy, which puts a pseudo-version like v0.0.0-20261023081318-c50a3efb03e0 in the adopter's committed go.mod. Rust gets bench-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 under chassis/. Go: bench copies go.mod and go.sum to a gitignored .bench/go.dev.mod and .bench/go.dev.sum, adds a replace onto the checkout, and runs go mod tidy and go build with -modfile, so the committed go.mod never gets a local path. Rust: a path dependency in the generated workspace.
  • The labbench_tools.go anchor blank-imports the auth package so tidy keeps the require.

Wiring

  • Go main.go.template serves auth.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.template adds .layer(BearerAuthLayer::new()) innermost, directly after register_services(). LabKit's access log, trace, correlation and metrics layers still record rejected requests, and Router::layer covers 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.Error response: a text/plain body of unauthorized, per docs/design/http-adapter-contract.md.

CI and docs

  • The --release integration jobs build bench with BENCH_VERSION and BENCH_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) and test:chassis:rust (fmt, clippy -D warnings, nextest, cargo deny with the root deny.toml). Each runs only when its directory changes.
  • AGENTS.md lists chassis/ and both gates; ARCHITECTURE.md describes the pin under build.
  • README.md notes that a cargo install bench is a dev build that reads the chassis from Cargo's checkout, and points adopters to the release install.
  • authn.md now 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 , and Bearer (no separator), all 401. Bearer x and bearer x pass, 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.sh and tests/integration-rust.sh now send a token on every route and check that missing, Basic x and Bearer get 401, that the 401 body is unauthorized, and that bearer x passes. Both pass locally against uncommitted checkout changes (Go ran against .bench/go.dev.mod with the committed go.mod untouched; cargo built bench-chassis from the checkout path), and both servers logged the warning.
  • The --release variants (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 to #87

Related to #110 (part B here; part A deferred, see the issue)

🤖 Generated with Claude Code

Edited by Lucas Charles

Merge request reports

Loading
Loading