From 72103e499094c1340215be0052e3d51ef9501e8e Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 16:31:19 +0000 Subject: [PATCH 1/3] fix(rest): serve API docs with ReDoc so zip leaves the tree utoipa-swagger-ui (every release to 10.0.1) builds against zip ^8.6, and RUSTSEC-2026-0367/0368/0369 are fixed only in zip >= 9. No patched 8.x exists, so #439 had to ignore all three in .cargo/audit.toml. Serve the OpenAPI spec at /api-docs/openapi.json as before and render it with utoipa-redoc at /redoc. zip, flate2 and seven other build-only crates drop out of Cargo.lock, and the audit ignores are deleted: cargo audit is clean with no exemptions. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3 --- .cargo/audit.toml | 15 ----- Cargo.lock | 102 ++------------------------------- README.adoc | 2 +- src/interfaces/README.adoc | 4 +- src/interfaces/rest/Cargo.toml | 2 +- src/interfaces/rest/main.rs | 14 +++-- 6 files changed, 18 insertions(+), 121 deletions(-) delete mode 100644 .cargo/audit.toml diff --git a/.cargo/audit.toml b/.cargo/audit.toml deleted file mode 100644 index 002e847c..00000000 --- a/.cargo/audit.toml +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# cargo-audit configuration (read by `cargo audit` from .cargo/audit.toml). - -[advisories] -# zip 8.6.0 extraction advisories. zip is reached only as a *build* -# dependency of utoipa-swagger-ui (src/interfaces/rest), whose build script -# unpacks the pinned Swagger UI archive; no echidna binary links zip or -# extracts untrusted archives at runtime. Every utoipa-swagger-ui release up -# to 10.0.1 requires zip ^8.6, so the >=9.0.0 fix cannot be selected yet. -# Remove these entries once utoipa-swagger-ui accepts zip >=9. -ignore = [ - "RUSTSEC-2026-0367", # SUID/SGID bits preserved during extraction - "RUSTSEC-2026-0368", # extract() symlinks pointing outside destination - "RUSTSEC-2026-0369", # extract() applies permissions through symlinks -] diff --git a/Cargo.lock b/Cargo.lock index e60041f2..37a9ba77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,12 +64,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "aho-corasick" version = "1.1.4" @@ -732,15 +726,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - [[package]] name = "criterion" version = "0.8.2" @@ -1199,7 +1184,7 @@ dependencies = [ "tracing", "tracing-subscriber", "utoipa", - "utoipa-swagger-ui", + "utoipa-redoc", "uuid", ] @@ -1323,16 +1308,6 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" -[[package]] -name = "flate2" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" -dependencies = [ - "miniz_oxide", - "zlib-rs", -] - [[package]] name = "fnv" version = "1.0.7" @@ -2070,26 +2045,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - [[package]] name = "mio" version = "1.2.1" @@ -3434,12 +3389,6 @@ dependencies = [ "wide", ] -[[package]] -name = "simd-adler32" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" - [[package]] name = "slab" version = "0.4.12" @@ -4075,12 +4024,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "typed-path" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" - [[package]] name = "typed-wasm" version = "0.1.0" @@ -4197,20 +4140,15 @@ dependencies = [ ] [[package]] -name = "utoipa-swagger-ui" -version = "10.0.1" +name = "utoipa-redoc" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f5ec9d7816e4ce8ccb7e0bd7276e090cad0fcb1def4f3540e5b0f7485d7583e" +checksum = "eab923f05c427c0d0729f292d84a74e1c7b34bb97463448fec1492cc4a9e7262" dependencies = [ "axum", - "base64 0.23.1", - "mime_guess", - "regex", "serde", "serde_json", - "url", "utoipa", - "zip", ] [[package]] @@ -4907,40 +4845,8 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "zip" -version = "8.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" -dependencies = [ - "crc32fast", - "flate2", - "indexmap", - "memchr", - "typed-path", - "zopfli", -] - -[[package]] -name = "zlib-rs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" - [[package]] name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" - -[[package]] -name = "zopfli" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" -dependencies = [ - "bumpalo", - "crc32fast", - "log", - "simd-adler32", -] diff --git a/README.adoc b/README.adoc index 64acfbf2..a476ff00 100644 --- a/README.adoc +++ b/README.adoc @@ -191,7 +191,7 @@ shape (Idris2 / Agda case studies in link:src/chapel/[`+src/chapel/+`]). * *Three API surfaces*: ** GraphQL (async-graphql, port 8081) ** gRPC (tonic + Protocol Buffers, port 50051) -** REST (axum + OpenAPI/Swagger, port 8000) +** REST (axum + OpenAPI/ReDoc, port 8000) * *AffineScript / AffineScript UI*: AffineScript components are being ported to AffineScript-TEA as the stdlib primitives needed for the port (Http / Promise / Json / Dict) land in diff --git a/src/interfaces/README.adoc b/src/interfaces/README.adoc index a8fce6d4..b7f185e8 100644 --- a/src/interfaces/README.adoc +++ b/src/interfaces/README.adoc @@ -37,10 +37,10 @@ CancelProof * *Framework:* Rust + axum + utoipa (OpenAPI) * *Port:* 8000 -* *Swagger UI:* http://localhost:8000/swagger-ui +* *API docs (ReDoc):* http://localhost:8000/redoc (raw spec: `+/api-docs/openapi.json+`) * *Features:* ** RESTful JSON API -** OpenAPI 3.0 specification with Swagger UI +** OpenAPI 3.0 specification rendered with ReDoc ** Standard HTTP verbs (GET, POST, DELETE) ** Endpoints: `+/api/v1/provers+`, `+/api/v1/proofs+`, `+/api/v1/proofs/:id/tactics+` diff --git a/src/interfaces/rest/Cargo.toml b/src/interfaces/rest/Cargo.toml index f8195993..ce6f9fa2 100644 --- a/src/interfaces/rest/Cargo.toml +++ b/src/interfaces/rest/Cargo.toml @@ -40,7 +40,7 @@ uuid = { version = "1.25.0", features = ["serde"] } # ids are minted by echidna # OpenAPI utoipa = { version = "6.0", features = ["axum_extras"] } -utoipa-swagger-ui = { version = "10.0", features = ["axum"] } +utoipa-redoc = { version = "7.0", features = ["axum"] } # ECHIDNA core echidna = { path = "../../.." } diff --git a/src/interfaces/rest/main.rs b/src/interfaces/rest/main.rs index f4cd532f..94371ac1 100644 --- a/src/interfaces/rest/main.rs +++ b/src/interfaces/rest/main.rs @@ -14,7 +14,7 @@ use std::time::Duration; use tokio::sync::{Mutex, RwLock}; use tower_http::cors::CorsLayer; use utoipa::OpenApi; -use utoipa_swagger_ui::SwaggerUi; +use utoipa_redoc::{Redoc, Servable}; mod ffi_wrapper; mod handlers; @@ -117,14 +117,20 @@ async fn main() { // Consultant-mode Q&A — free-form question + optional context → // LLM-shaped markdown answer via BoJ's cartridge router. .route("/api/v1/consult", post(handlers::consult)) - // OpenAPI documentation - .merge(SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", ApiDoc::openapi())) + // OpenAPI documentation: the raw spec, and ReDoc rendering it. + // ReDoc replaced Swagger UI because utoipa-swagger-ui builds + // against zip ^8.6, which has no fix for RUSTSEC-2026-0367..0369. + .route( + "/api-docs/openapi.json", + get(|| async { axum::Json(ApiDoc::openapi()) }), + ) + .merge(Redoc::with_url("/redoc", ApiDoc::openapi())) .layer(CorsLayer::permissive()) .with_state(state); let addr = std::env::var("ECHIDNA_REST_ADDR").unwrap_or_else(|_| "127.0.0.1:8000".to_string()); tracing::info!("REST API listening on http://{}", addr); - tracing::info!("Swagger UI available at http://{}/swagger-ui", addr); + tracing::info!("API docs (ReDoc) available at http://{}/redoc", addr); let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); axum::serve(listener, app).await.unwrap(); From 1092345cbe7b52ab7505348fdf17b7a1254c2c4f Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Mon, 19 Oct 2026 22:24:08 +0000 Subject: [PATCH 2/3] docs(rest): document API startup configuration and panic conditions --- src/interfaces/rest/main.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/interfaces/rest/main.rs b/src/interfaces/rest/main.rs index 94371ac1..0f99a4a4 100644 --- a/src/interfaces/rest/main.rs +++ b/src/interfaces/rest/main.rs @@ -51,6 +51,17 @@ pub struct ProofSession { pub start_time: std::time::Instant, } +/// Runs the REST API with permissive CORS, ReDoc at `/redoc` and the OpenAPI +/// JSON specification at `/api-docs/openapi.json`. +/// +/// Binds to `ECHIDNA_REST_ADDR`, defaulting to `127.0.0.1:8000` when the variable +/// is absent or is not valid Unicode. Probes Julia ML at `http://127.0.0.1:8090` +/// and initialises the FFI layer; failures of either check do not prevent startup. +/// +/// # Panics +/// +/// Panics if tracing initialisation, HTTP client creation, listener binding or +/// serving fails. #[tokio::main] async fn main() { tracing_subscriber::fmt() From 78a70c2742b2e4ff234ef23b88dbb7e0ae2e122d Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Mon, 19 Oct 2026 22:28:21 +0000 Subject: [PATCH 3/3] fix(ci): exclude nested js-runtimes checker from Cargo workspace --- Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 36417740..228eba6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -157,4 +157,6 @@ members = [ ] exclude = [ "fuzz", + # The governance workflow builds this external checker in a nested checkout. + ".standards-js/tools/js-runtimes", ]