diff --git a/.audit_ignore b/.audit_ignore index baef8735..5d772a43 100644 --- a/.audit_ignore +++ b/.audit_ignore @@ -58,54 +58,3 @@ EEF-CVE-2026-43966 # RETIRE the moment cowlib publishes a release that validates cookie/1, and # move the lock to that release. EEF-CVE-2026-43969 - -# mint advisories. Verified 2026-09-28 against the ERLEF CNA records that -# hex.audit serves (https://api.osv.dev/v1/vulns/) and the mint 1.10.1 and -# 1.11.0 sources. -# -# Shared facts. mint 1.11.0 fixes all three, and mix.lock holds 1.10.1 anyway. -# mint 1.11.0 no longer closes an HTTP/1 connection on a receive timeout (the -# `{:error, %Mint.TransportError{reason: :timeout}}` clause of -# Mint.HTTP1.recv/3), and Finch 0.23.0, the newest release, returns any open -# connection to its pool (transfer_if_open in lib/finch/http1/pool.ex). The -# next request on that connection is written behind the unanswered one and -# times out, and so does a retry that lands there; if the server answers late, -# a later request on it raises CaseClauseError inside Finch. On 1.10.1 the -# retry opens a new connection. test/timed_out_connection_test.exs fails on -# 1.11.0 with Finch 0.23.0 and passes on 1.10.1. Req and ReqLLM speak HTTP/1 -# unless a caller configures otherwise (Req's default protocols are [:http1]; -# ReqLLM's @default_stream_pool_protocols is [:http1]), and Imp opens HTTP/2 -# only when a caller asks, through the benchmark parity task's -# --req-llm-pool-protocols. -# RETIRE all three together when a Finch release closes a connection that -# still has a request in flight, such as one that includes -# https://github.com/sneako/finch/pull/397 ("Close abandoned HTTP/1 -# connections after request errors", open and unreleased on 2026-09-28), or -# when a mint release closes the connection on a receive timeout again. Then -# move the lock to that Finch release and mint 1.11 in the same change, and -# the timed-out-connection test must still pass. - -# EEF-CVE-2026-91043 / CVE-2026-91043 / GHSA-9x8p-qrf4-jq7g (HIGH) - HPACK -# indexed cookie fields in a Mint HTTP/2 response bypass max_header_list_size -# and exhaust client memory. HTTP/2 only (Mint.HTTP2): not reachable through -# Imp's HTTP/1 default. Reachable in an application that configures HTTP/2 -# for Req or ReqLLM against a malicious server. Retire as above. -EEF-CVE-2026-91043 - -# EEF-CVE-2026-92103 / CVE-2026-92103 / GHSA-q95c-ccq6-j5j6 (MEDIUM) - the -# Mint HTTP/2 client buffers a frame up to 16 MiB before enforcing -# max_frame_size. HTTP/2 only (Mint.HTTP2.Frame): not reachable through Imp's -# HTTP/1 default. Retire as above. -EEF-CVE-2026-92103 - -# EEF-CVE-2026-94194 / CVE-2026-94194 / GHSA-gvrc-75rc-7gj9 (MEDIUM) - the -# Mint HTTP/1 client applies chunked framing when chunked is not the final -# transfer coding, and keeps an HTTP/1.0 connection open after a response with -# Transfer-Encoding. This one is HTTP/1 and is reachable: a malicious server -# behind an intermediary that follows RFC 9112 can desynchronize the -# intermediary and Mint on a pooled connection and poison the responses to -# later requests. It needs both the malicious server and such an intermediary -# between it and Imp. It is ignored because the fix comes only with mint -# 1.11.0, whose timeout behaviour breaks every HTTP/1 client of Finch 0.23.0, -# not because it is a false positive. Retire as above. -EEF-CVE-2026-94194 diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ff790a8..48d7f920 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ User-visible changes to Imp are recorded here. +## Unreleased + +### Security + +- Imp requires `finch` `~> 0.24`, and its lock file and the example projects' + take `finch` 0.24.0 with `mint` 1.11.0. Finch 0.24.0 closes an HTTP/1 + connection a request timed out on, so `mint` 1.11.0 no longer makes the + next request on that connection fail, and the lock no longer holds `mint` + 1.10.1. That removes the three `mint` advisories (EEF-CVE-2026-91043, + EEF-CVE-2026-92103, EEF-CVE-2026-94194) from `.audit_ignore` and the + Known limits entry from the release notes. Migration: an application that + added `{:mint, "~> 1.10.1"}` for this removes it; one whose lock has + `finch` below 0.24 runs `mix deps.update finch mint hpax`. + ## 0.7.0 — 2026-09-28 ### Changed diff --git a/examples/deployment/mix.lock b/examples/deployment/mix.lock index 4db647e2..724d068d 100644 --- a/examples/deployment/mix.lock +++ b/examples/deployment/mix.lock @@ -10,8 +10,8 @@ "erlexec": {:hex, :erlexec, "2.4.1", "73d2c49ecf3709cd7791a0affbef466a11cc1ecf9d679c504edbc9824b35c593", [:rebar3], [], "hexpm", "c92e1776eb1f7eee357a799cf399013dfa672ab50b4f507dfdcdeee11ca89769"}, "ex_json_schema": {:hex, :ex_json_schema, "0.11.5", "ea45f3238be135949dbbbcc9e8eb4682d6e561b8a66374e75d85a2e1d2bd4107", [:mix], [{:decimal, "~> 3.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "61ed2a8f07bd115e7ab6d45c147642a8c73b962bc419fadbb248046b9d3d0f20"}, "ex_mcp": {:hex, :ex_mcp, "1.5.0", "bf0a6862b306d4ba76c29848db110b49d1cbe83b304c9d1ba2ea6b09a7f83b9a", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:ex_json_schema, "~> 0.10", [hex: :ex_json_schema, repo: "hexpm", optional: false]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.11", [hex: :jose, repo: "hexpm", optional: false]}, {:mint, "~> 1.6", [hex: :mint, repo: "hexpm", optional: false]}, {:mint_web_socket, "~> 1.0", [hex: :mint_web_socket, repo: "hexpm", optional: false]}, {:plug, "~> 1.16", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3cb3cd60e2275277f519ec6db02cf5e92b342d88c5ba0d31e31bca498b28e4fb"}, - "finch": {:hex, :finch, "0.23.0", "e3f9287ac25a8832f848b144c2b57346aac65b205e2e0629a52adfe6507fd837", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.8", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "80e58d3f936f57e3fdf404f83a3642897ae6d9fb642934e46da4d8fe761b99d5"}, - "hpax": {:hex, :hpax, "1.0.4", "777de5d433b0fbdc7c418159c8055910faa8047ffdb3d6b31098d2a46cd7685c", [:mix], [], "hexpm", "afc7cb142ebcc2d01ce7816190b98ce5dd49e799111b24249f3443d730f377ca"}, + "finch": {:hex, :finch, "0.24.0", "4022b6194e907b6d9b597c168001cac38e488a35fe36cef9d8297e3159782510", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.8", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "33ba40069c3587c2f99f9125b766e19dad87d6d54be3c6961db2304df04cef00"}, + "hpax": {:hex, :hpax, "1.1.0", "782931867cc23217c68fb5f68fe1a11f5e7544c7fda82c8a7019a5df5a4a1cdf", [:mix], [], "hexpm", "0b8d0f05832f55571d65ac720f79bf8994138ffbb133209dc4685eae0ad456a8"}, "idna": {:hex, :idna, "7.1.0", "1067a13043538129602d2f2ce6899d8713125c7d19734aa557ce2e3ea55bd4f1", [:rebar3], [], "hexpm", "6ae959a025bf36df61a8cab8508d9654891b5426a84c44d82deaffd6ddf8c71f"}, "jason": {:hex, :jason, "1.4.5", "2e3a008590b0b8d7388c20293e9dcc9cf3e5d642fd2a114e4cbbb52e595d940a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b0c823996102bcd0239b3c2444eb00409b72f6a140c1950bc8b457d836b30684"}, "jaxon": {:hex, :jaxon, "2.0.8", "00951a79d354260e28d7e36f956c3de94818124768a4b22e0fc55559d1b3bfe7", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "74532853b1126609615ea98f0ceb5009e70465ca98027afbbd8ed314d887e82d"}, @@ -19,7 +19,7 @@ "jsv": {:hex, :jsv, "0.24.0", "71b521244b51e1849ac7cae986ce391ae13f6ffb781235ad046a4f7ebbb9472b", [:mix], [{:abnf_parsec, "~> 2.0", [hex: :abnf_parsec, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0 or ~> 3.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:idna, "~> 6.0 or ~> 7.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:texture, ">= 1.2.1", [hex: :texture, repo: "hexpm", optional: false]}], "hexpm", "a9829510d25fe6e16a84600ba8d2f7c3da5234401b796aa87741393b1c85aa27"}, "llm_db": {:hex, :llm_db, "2026.9.5", "357a594559c194f65616787961badde1256d5078992639b771437ef3e039d1e5", [:mix], [{:dotenvy, "~> 1.1", [hex: :dotenvy, repo: "hexpm", optional: false]}, {:igniter, "~> 0.7", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:toml, "~> 0.7", [hex: :toml, repo: "hexpm", optional: false]}, {:zoi, "~> 0.10", [hex: :zoi, repo: "hexpm", optional: false]}], "hexpm", "8631c05b435ebedade83421d3d8b72b051af2caee822d953a21384cad95a9714"}, "mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"}, - "mint": {:hex, :mint, "1.10.1", "c53e70867cf74017716884d8d33e0742b08b32e9cdb0031cbc69a429dc5555e3", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "0ba2a904605ed8406393444fb8b3356dc58eb59ee6c7fb94ac3f015e1be129e8"}, + "mint": {:hex, :mint, "1.11.0", "a713551624815c0435237b93d90ea8b9b14254690c66f732d0ef8930f76ff1d9", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "c6279ba2d6aa3a383a1d4cfbe7b59f42e6efd400f58d8e2acfeac48a438693ab"}, "mint_web_socket": {:hex, :mint_web_socket, "1.0.6", "5ffcf350df5b90f2d7a04adf877165228804993714592512374218d4679e325a", [:mix], [{:mint, ">= 1.4.1 and < 2.0.0-0", [hex: :mint, repo: "hexpm", optional: false]}], "hexpm", "0c360e9012413f1c115a63532601eb5d63731aab7010949178769760686c1698"}, "nimble_csv": {:hex, :nimble_csv, "1.3.0", "b7f998dc62b222bce9596e46f028c7a5af04cb5dde6df2ea197c583227c54971", [:mix], [], "hexpm", "41ccdc18f7c8f8bb06e84164fc51635321e80d5a3b450761c4997d620925d619"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, diff --git a/examples/workspace_agent/mix.lock b/examples/workspace_agent/mix.lock index 5d382494..e5ec7e12 100644 --- a/examples/workspace_agent/mix.lock +++ b/examples/workspace_agent/mix.lock @@ -10,8 +10,8 @@ "erlexec": {:hex, :erlexec, "2.3.4", "91e8374e269d82cce0d5cbb47ebc8a4810d56474a767a5575ab22b40cf6ff5f9", [:rebar3], [], "hexpm", "ab0c6c3569a9f991fbfe6624961a88688610738589ff9dbad24db9bb27ae233b"}, "ex_json_schema": {:hex, :ex_json_schema, "0.11.5", "ea45f3238be135949dbbbcc9e8eb4682d6e561b8a66374e75d85a2e1d2bd4107", [:mix], [{:decimal, "~> 3.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "61ed2a8f07bd115e7ab6d45c147642a8c73b962bc419fadbb248046b9d3d0f20"}, "ex_mcp": {:hex, :ex_mcp, "1.5.0", "bf0a6862b306d4ba76c29848db110b49d1cbe83b304c9d1ba2ea6b09a7f83b9a", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:ex_json_schema, "~> 0.10", [hex: :ex_json_schema, repo: "hexpm", optional: false]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.11", [hex: :jose, repo: "hexpm", optional: false]}, {:mint, "~> 1.6", [hex: :mint, repo: "hexpm", optional: false]}, {:mint_web_socket, "~> 1.0", [hex: :mint_web_socket, repo: "hexpm", optional: false]}, {:plug, "~> 1.16", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3cb3cd60e2275277f519ec6db02cf5e92b342d88c5ba0d31e31bca498b28e4fb"}, - "finch": {:hex, :finch, "0.23.0", "e3f9287ac25a8832f848b144c2b57346aac65b205e2e0629a52adfe6507fd837", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.8", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "80e58d3f936f57e3fdf404f83a3642897ae6d9fb642934e46da4d8fe761b99d5"}, - "hpax": {:hex, :hpax, "1.0.4", "777de5d433b0fbdc7c418159c8055910faa8047ffdb3d6b31098d2a46cd7685c", [:mix], [], "hexpm", "afc7cb142ebcc2d01ce7816190b98ce5dd49e799111b24249f3443d730f377ca"}, + "finch": {:hex, :finch, "0.24.0", "4022b6194e907b6d9b597c168001cac38e488a35fe36cef9d8297e3159782510", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.8", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "33ba40069c3587c2f99f9125b766e19dad87d6d54be3c6961db2304df04cef00"}, + "hpax": {:hex, :hpax, "1.1.0", "782931867cc23217c68fb5f68fe1a11f5e7544c7fda82c8a7019a5df5a4a1cdf", [:mix], [], "hexpm", "0b8d0f05832f55571d65ac720f79bf8994138ffbb133209dc4685eae0ad456a8"}, "idna": {:hex, :idna, "7.1.0", "1067a13043538129602d2f2ce6899d8713125c7d19734aa557ce2e3ea55bd4f1", [:rebar3], [], "hexpm", "6ae959a025bf36df61a8cab8508d9654891b5426a84c44d82deaffd6ddf8c71f"}, "jason": {:hex, :jason, "1.4.5", "2e3a008590b0b8d7388c20293e9dcc9cf3e5d642fd2a114e4cbbb52e595d940a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b0c823996102bcd0239b3c2444eb00409b72f6a140c1950bc8b457d836b30684"}, "jaxon": {:hex, :jaxon, "2.0.8", "00951a79d354260e28d7e36f956c3de94818124768a4b22e0fc55559d1b3bfe7", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "74532853b1126609615ea98f0ceb5009e70465ca98027afbbd8ed314d887e82d"}, @@ -19,7 +19,7 @@ "jsv": {:hex, :jsv, "0.22.0", "3a2bb35dd7d1ca0034437bee8099214e40d391a5e4f058f5a0800aef91c4dfeb", [:mix], [{:abnf_parsec, "~> 2.0", [hex: :abnf_parsec, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0 or ~> 3.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:idna, "~> 6.0 or ~> 7.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:texture, ">= 1.2.1", [hex: :texture, repo: "hexpm", optional: false]}], "hexpm", "79bae1f970413c86771051a8ea0bd553cc1e866d285270be539f1ef3ca044f3c"}, "llm_db": {:hex, :llm_db, "2026.7.5", "38e345e753b027f095e9eb01157de911c1e75d5ac7d760042f771cbdeabb08c1", [:mix], [{:dotenvy, "~> 1.1", [hex: :dotenvy, repo: "hexpm", optional: false]}, {:igniter, "~> 0.7", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:toml, "~> 0.7", [hex: :toml, repo: "hexpm", optional: false]}, {:zoi, "~> 0.10", [hex: :zoi, repo: "hexpm", optional: false]}], "hexpm", "93ceaf3448b8cea11358854388e83480ed4e84e39adc0af8a3629935d3d5dd7c"}, "mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"}, - "mint": {:hex, :mint, "1.10.1", "c53e70867cf74017716884d8d33e0742b08b32e9cdb0031cbc69a429dc5555e3", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "0ba2a904605ed8406393444fb8b3356dc58eb59ee6c7fb94ac3f015e1be129e8"}, + "mint": {:hex, :mint, "1.11.0", "a713551624815c0435237b93d90ea8b9b14254690c66f732d0ef8930f76ff1d9", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "c6279ba2d6aa3a383a1d4cfbe7b59f42e6efd400f58d8e2acfeac48a438693ab"}, "mint_web_socket": {:hex, :mint_web_socket, "1.0.6", "5ffcf350df5b90f2d7a04adf877165228804993714592512374218d4679e325a", [:mix], [{:mint, ">= 1.4.1 and < 2.0.0-0", [hex: :mint, repo: "hexpm", optional: false]}], "hexpm", "0c360e9012413f1c115a63532601eb5d63731aab7010949178769760686c1698"}, "nimble_csv": {:hex, :nimble_csv, "1.3.0", "b7f998dc62b222bce9596e46f028c7a5af04cb5dde6df2ea197c583227c54971", [:mix], [], "hexpm", "41ccdc18f7c8f8bb06e84164fc51635321e80d5a3b450761c4997d620925d619"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, diff --git a/mix.exs b/mix.exs index 4ab03b71..712b3666 100644 --- a/mix.exs +++ b/mix.exs @@ -132,19 +132,18 @@ defmodule Imp.MixProject do # something else brings it. {:decimal, "~> 2.0 or ~> 3.0", optional: true}, # Imp.Clients.ReqLLM matches Finch's error structs (Finch.TransportError, - # Finch.Error) to tell a request that was never sent; 0.21 is Req's floor. - {:finch, "~> 0.21"}, + # Finch.Error) to tell a request that was never sent. 0.24 is the first + # Finch that closes an HTTP/1 connection a request timed out on; before + # it, with mint 1.11, the pool reused that connection and every request + # after the timeout that drew it failed (test/timed_out_connection_test.exs). + {:finch, "~> 0.24"}, {:jason, "~> 1.4"}, {:jaxon, "~> 2.0.8"}, # Imp matches Mint's error structs (Mint.TransportError, Mint.HTTPError) # to tell a request that was never sent from one that may have run # (Imp.Clients.ReqLLM, Imp.MCP.CallFailure), so it depends on Mint # directly. The requirement is Finch's own, so declaring it moves no - # application's lock. It is not 1.11: mint 1.11.0 leaves an HTTP/1 - # connection open after a receive timeout and Finch 0.23.0 reuses it, so - # mix.lock holds 1.10.1 (test/timed_out_connection_test.exs, - # .audit_ignore) until a Finch release includes - # https://github.com/sneako/finch/pull/397. + # application's lock. {:mint, "~> 1.8"}, {:nimble_csv, "~> 1.3"}, {:nimble_options, "~> 1.1"}, diff --git a/mix.lock b/mix.lock index a0c22d51..45e08541 100644 --- a/mix.lock +++ b/mix.lock @@ -18,8 +18,8 @@ "ex_json_schema": {:hex, :ex_json_schema, "0.11.5", "ea45f3238be135949dbbbcc9e8eb4682d6e561b8a66374e75d85a2e1d2bd4107", [:mix], [{:decimal, "~> 3.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "61ed2a8f07bd115e7ab6d45c147642a8c73b962bc419fadbb248046b9d3d0f20"}, "ex_mcp": {:hex, :ex_mcp, "1.5.0", "bf0a6862b306d4ba76c29848db110b49d1cbe83b304c9d1ba2ea6b09a7f83b9a", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:ex_json_schema, "~> 0.10", [hex: :ex_json_schema, repo: "hexpm", optional: false]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.11", [hex: :jose, repo: "hexpm", optional: false]}, {:mint, "~> 1.6", [hex: :mint, repo: "hexpm", optional: false]}, {:mint_web_socket, "~> 1.0", [hex: :mint_web_socket, repo: "hexpm", optional: false]}, {:plug, "~> 1.16", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3cb3cd60e2275277f519ec6db02cf5e92b342d88c5ba0d31e31bca498b28e4fb"}, "file_system": {:hex, :file_system, "1.1.1", "31864f4685b0148f25bd3fbef2b1228457c0c89024ad67f7a81a3ffbc0bbad3a", [:mix], [], "hexpm", "7a15ff97dfe526aeefb090a7a9d3d03aa907e100e262a0f8f7746b78f8f87a5d"}, - "finch": {:hex, :finch, "0.23.0", "e3f9287ac25a8832f848b144c2b57346aac65b205e2e0629a52adfe6507fd837", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.8", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "80e58d3f936f57e3fdf404f83a3642897ae6d9fb642934e46da4d8fe761b99d5"}, - "hpax": {:hex, :hpax, "1.0.4", "777de5d433b0fbdc7c418159c8055910faa8047ffdb3d6b31098d2a46cd7685c", [:mix], [], "hexpm", "afc7cb142ebcc2d01ce7816190b98ce5dd49e799111b24249f3443d730f377ca"}, + "finch": {:hex, :finch, "0.24.0", "4022b6194e907b6d9b597c168001cac38e488a35fe36cef9d8297e3159782510", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.8", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "33ba40069c3587c2f99f9125b766e19dad87d6d54be3c6961db2304df04cef00"}, + "hpax": {:hex, :hpax, "1.1.0", "782931867cc23217c68fb5f68fe1a11f5e7544c7fda82c8a7019a5df5a4a1cdf", [:mix], [], "hexpm", "0b8d0f05832f55571d65ac720f79bf8994138ffbb133209dc4685eae0ad456a8"}, "idna": {:hex, :idna, "7.1.0", "1067a13043538129602d2f2ce6899d8713125c7d19734aa557ce2e3ea55bd4f1", [:rebar3], [], "hexpm", "6ae959a025bf36df61a8cab8508d9654891b5426a84c44d82deaffd6ddf8c71f"}, "jason": {:hex, :jason, "1.4.5", "2e3a008590b0b8d7388c20293e9dcc9cf3e5d642fd2a114e4cbbb52e595d940a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b0c823996102bcd0239b3c2444eb00409b72f6a140c1950bc8b457d836b30684"}, "jaxon": {:hex, :jaxon, "2.0.8", "00951a79d354260e28d7e36f956c3de94818124768a4b22e0fc55559d1b3bfe7", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "74532853b1126609615ea98f0ceb5009e70465ca98027afbbd8ed314d887e82d"}, @@ -30,7 +30,7 @@ "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, "makeup_erlang": {:hex, :makeup_erlang, "1.1.0", "835f7e60792e08824cda445639555d7bf1bbbddb1b60b306e33cb6f6db24dc74", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "1cd6780fb1dd1a03979abaed0fe82712b0625118fd5257d3ebbf73f960c73c3c"}, "mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"}, - "mint": {:hex, :mint, "1.10.1", "c53e70867cf74017716884d8d33e0742b08b32e9cdb0031cbc69a429dc5555e3", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "0ba2a904605ed8406393444fb8b3356dc58eb59ee6c7fb94ac3f015e1be129e8"}, + "mint": {:hex, :mint, "1.11.0", "a713551624815c0435237b93d90ea8b9b14254690c66f732d0ef8930f76ff1d9", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "c6279ba2d6aa3a383a1d4cfbe7b59f42e6efd400f58d8e2acfeac48a438693ab"}, "mint_web_socket": {:hex, :mint_web_socket, "1.0.6", "5ffcf350df5b90f2d7a04adf877165228804993714592512374218d4679e325a", [:mix], [{:mint, ">= 1.4.1 and < 2.0.0-0", [hex: :mint, repo: "hexpm", optional: false]}], "hexpm", "0c360e9012413f1c115a63532601eb5d63731aab7010949178769760686c1698"}, "mix_audit": {:hex, :mix_audit, "2.1.5", "c0f77cee6b4ef9d97e37772359a187a166c7a1e0e08b50edf5bf6959dfe5a016", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "87f9298e21da32f697af535475860dc1d3617a010e0b418d2ec6142bc8b42d69"}, "mox": {:hex, :mox, "1.3.2", "f34ca4331b1cce3125609c6de674739fe5f3df0d68df25510d64b6a94b2246de", [:mix], [{:nimble_ownership, "~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}], "hexpm", "97918a185e727f3128a826f01827b5b8168e1b815bda19eb4192c3ffdb6a8054"}, diff --git a/test/timed_out_connection_test.exs b/test/timed_out_connection_test.exs index 90b9bc7f..d84a4bf8 100644 --- a/test/timed_out_connection_test.exs +++ b/test/timed_out_connection_test.exs @@ -1,19 +1,12 @@ defmodule Imp.TimedOutConnectionTest do use ExUnit.Case, async: true - # This test is why Imp's lock holds mint 1.10.1 rather than 1.11.0. - # - # mint 1.11.0 leaves an HTTP/1 connection open after a receive timeout, with - # the request still in flight, and Finch 0.23.0 returns any open connection to - # its pool. The next request that pool gives that connection is written behind - # the one that was never answered, so it times out too, and so does every - # retry that lands there. On mint 1.10.1 the timeout closes the connection and - # the next request opens a new one. - # - # The Finch fix is https://github.com/sneako/finch/pull/397 ("Close abandoned - # HTTP/1 connections after request errors"), which is open and in no release. - # When a Finch release includes it, the lock takes that release and mint 1.11 - # together, and this test passes on both. + # mint 1.11 leaves an HTTP/1 connection open after a receive timeout, with + # the request still in flight. Finch closes such a connection rather than + # returning it to its pool (from 0.24.0, which mix.exs requires), so the next + # request opens a new connection. A pool that reused it would write the next + # request behind the one that was never answered, and that request would time + # out or fail when the late answer arrived. @completion %{ "id" => "late",