Skip to content

continuous integration

Kadyapam edited this page Oct 4, 2026 · 2 revisions

Continuous Integration

.github/workflows/test.yml is the gateway's pre-merge gate, running on pull_request and on pushes to main.

step command
build cargo build --all-targets --locked
test cargo test --all-targets --locked
clippy cargo clippy --all-targets --locked -- -D warnings

--all-targets is deliberate: plain cargo build / cargo test skip integration tests and cfg(test)-only code, so the noetl-gateway binary can be broken while the library compiles clean.

clippy gates, with no allow-list

As of noetl/ai-meta#378 clippy runs with -D warnings and no -A exceptions — any new lint fails the build.

It previously ran as cargo clippy … || true: the step was visible in every PR log and could never fail. Four pre-existing lints had to be cleared before the flip, since a bare flip would have started red for reasons no PR caused:

site lint fix
src/config/gateway_config.rs:180 derivable_impls manual impl Default → #[derive(Default)]
src/config/postgresql_env.rs:31 let_and_return return the parse expression directly
src/graphql/schema.rs:128, :208 map_clone .map(|s| s.clone()) → .cloned()

The GatewayConfig::default() change, and why it is safe

Worth recording because it touches config loading. The manual impl Default for GatewayConfig set every field to that field's own Default, so #[derive(Default)] is equivalent. GatewayConfig also carries #[serde(default)], which means serde fills missing TOML fields from Default::default() — the derive calls each field's Default exactly as the manual impl did, so parsing behaviour is unchanged.

That is covered, not just argued: test_default_config asserts three nested values through GatewayConfig::default() (server.port == 8090, noetl.base_url, auth_playbooks.login), and test_toml_parsing exercises the #[serde(default)] fill. If someone replaces the derive with something non-equivalent, those fail.

If you add an -A, put the reason on the same line. An unexplained -A reads as configuration rather than debt, and nothing revisits it.

The toolchain is pinned here

rust-toolchain.toml pins channel = "1.99.0". The workflow installs dtolnay/rust-toolchain@stable, but the pin wins when cargo runs, so clippy's lint set is stable: it moves only when someone edits that file. Every Rust repo in the fleet now carries the same pin, so no gate can go red from a Rust release alone. Raised from 1.91.1 on 2026-10-04 (noetl/gateway#54, noetl/ai-meta#398).

When reading the toolchain out of a CI log, use the version in the lint's own rust-clippy/rust-<x.y.z> documentation URL. The dtolnay/rust-toolchain banner says what it installed, not what the pin then selected.

⚠⚠ base64-compat made the crate un-buildable on 1.99.0

Raising the pin was expected to cost one lint. It cost one lint and a dependency removal, because cargo refused the build outright:

error[E0464]: multiple candidates for `rlib` dependency `base64` found

base64-compat = "1.0.0" declares [lib] name = "base64" in its own manifest, so once both it and the real base64 crate are in the graph there are two rlibs claiming the same crate name. It was referenced nowhere in gateway source — a dead dependency that had been dead long enough for the collision to go unnoticed. Removed in the same change.

Two things worth keeping from how this was found:

  • It reproduced on both toolchains locally, which is what made me call it a local artifact. A failure that reproduces everywhere reads like environment noise, which is the inverse of the usual tell. CI was the instrument that proved the location real — the error appeared in the gateway's own PR run.
  • A lint count taken with cargo clippy on the old toolchain cannot predict a compilation failure on the new one. Measure the pin bump by running the build, not only the linter.

The one lint, and why it is an #[allow]

clippy::result_large_err fires on auth_middleware. It is kept as a function-scoped #[allow] with the reason written above it, not fixed: axum's middleware signature is Result<Response, Response>, so the error variant is a whole Response by construction. Boxing it would mean fighting the framework's own type, and a crate-wide -A would hide the lint everywhere else it might be telling the truth.

Related

Clone this wiki locally