diff --git a/README.md b/README.md index 7ab8462a..031fcc76 100644 --- a/README.md +++ b/README.md @@ -549,6 +549,28 @@ Coverage data is imported after tests are run. See the `mix test` [Coverage documentation](https://hexdocs.pm/mix/Mix.Tasks.Test.html#module-coverage) for more information on `.coverdata`. +### Configuring HTTP Options in ExCoveralls + +You can customize the HTTP options used by [`:httpc`](https://www.erlang.org/doc/man/httpc.html) when posting results. The example below shows how to specify a custom `cacertfile`: + +```elixir +config :excoveralls, + http_options: [ + timeout: 10_000, + ssl: [ + # Refer to the secure coding guide: + # https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/inets + verify: :verify_peer, + depth: 2, + customize_hostname_check: [ + match_fun: :public_key.pkix_verify_hostname_match_fun(:https) + ], + cacertfile: to_charlist(System.fetch_env!("TEST_COVERAGE_CACERTFILE")) + ] +``` + +By default, ExCoveralls uses the `cacertfile` from [`castore`](https://hexdocs.pm/castore/api-reference.html) when the dependency is installed. If it's not available and you're running Erlang `25` or later, the system will attempt to use the OS certificates via [`:public_key.cacerts_load/0`](https://www.erlang.org/doc/man/public_key.html#cacerts_load-0). + ### Notes - If mock library is used, it will show some warnings during execution. - https://github.com/eproxus/meck/pull/17 diff --git a/lib/excoveralls/poster.ex b/lib/excoveralls/poster.ex index 4e5f3539..39e87514 100644 --- a/lib/excoveralls/poster.ex +++ b/lib/excoveralls/poster.ex @@ -59,18 +59,25 @@ defmodule ExCoveralls.Poster do body } - http_options = [ - timeout: 10_000, - ssl: - [ - verify: :verify_peer, - depth: 2, - customize_hostname_check: [ - match_fun: :public_key.pkix_verify_hostname_match_fun(:https) + http_options = + case Application.get_env(:excoveralls, :http_options) do + [_ | _] = options -> + options + + _ -> + [ + timeout: 10_000, + ssl: + [ + verify: :verify_peer, + depth: 2, + customize_hostname_check: [ + match_fun: :public_key.pkix_verify_hostname_match_fun(:https) + ] + # https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/inets + ] ++ cacert_option() ] - # https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/inets - ] ++ cacert_option() - ] + end case :httpc.request(:post, request, http_options, sync: true, body_format: :binary) do {:ok, {{_protocol, status_code, _status_message}, _headers, _body}} diff --git a/test/poster_test.exs b/test/poster_test.exs index 5e54fe02..e7d9f8f2 100644 --- a/test/poster_test.exs +++ b/test/poster_test.exs @@ -48,4 +48,26 @@ defmodule PosterTest do assert ExCoveralls.Poster.execute("{}", endpoint: endpoint) == :ok end) =~ ~r/maintenance/ end + + test "passes custom http options when configured", %{bypass: bypass, endpoint: endpoint} do + Application.put_env(:excoveralls, :http_options, autoredirect: false) + + on_exit(fn -> + Application.delete_env(:excoveralls, :http_options) + end) + + Bypass.expect_once(bypass, "POST", "/api/v1/jobs", fn conn -> + conn + |> Plug.Conn.put_resp_header("location", Path.join(endpoint, "redirected") |> IO.inspect()) + |> Plug.Conn.resp(302, "") + end) + + assert_raise( + ExCoveralls.ReportUploadError, + "Failed to upload the report to '#{endpoint}' (reason: status_code = 302, body = ).", + fn -> + ExCoveralls.Poster.execute("{}", endpoint: endpoint) == :ok + end + ) + end end