Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 6 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,29 @@ on:

jobs:
test:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
env:
MIX_ENV: test
strategy:
fail-fast: false
matrix:
include:
- pair:
elixir: 1.13
otp: 24
- pair:
elixir: 1.15
otp: 26
lint: lint
- pair:
elixir: 1.18
otp: 28
lint: lint
elixir: 1.19
otp: 28.2
lint: true
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- uses: erlef/setup-beam@v1
with:
otp-version: ${{matrix.pair.otp}}
elixir-version: ${{matrix.pair.elixir}}

- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
deps
Expand Down
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add support for the `NO_PROXY` environment variable.
With this env var, you can filter out hosts to avoid using
the configured proxy. Accepts a list of hosts separated
by a comma `","`.

- Add support for choosing the IP version to use, therefore supporting IPv6.
The environment variable `RUSTLER_PRECOMPILED_IPFAMILY` can be set to:
* "inet" - for IPv4 only. This is the default option.
* "inet6" - for IPv6 only.
* "inet6fb4" - for trying IPv6 first, and then fallback to IPv4.

### Changed

- Drop support for Elixir 1.13 and 1.14. Since those versions are
not supported anymore by the core team, they should be avoided.

- Rely on cert stores provided by Erlang/OTP +25.

This change removes the dependency on `castore` package in favour
of loading the cert stores from OTP. In case an older OTP version is
in use, a warning is emitted.

Notice that loading a cert file from the `HEX_CACERTS_PATH` env var
is still supported and has precedence over the OTP cert stores.

## [0.8.4] - 2025-12-08

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:rustler_precompiled, "~> 0.8"}
{:rustler_precompiled, "~> 0.9"}
]
end
```
Expand Down
78 changes: 63 additions & 15 deletions lib/rustler_precompiled.ex
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,13 @@ defmodule RustlerPrecompiled do

* `HTTPS_PROXY` or `https_proxy` - Sets the HTTPS proxy configuration.

* `NO_PROXY` - In case a proxy is set with the described env vars from above, this
option will make `:httpc` skip the proxy for the given hosts.
Use commas (,) to configure multiple hosts.

* `HEX_CACERTS_PATH` - Sets the path for a custom CA certificates file.
If unset, defaults to `CAStore.file_path/0`.
If unset, defaults to `:public.cacerts_get/0` (OTP >= 25) if available.
In case it's running on an old OTP version, a warning is emitted.

* `MIX_XDG` - If present, sets the OS as `:linux` for the `:filename.basedir/3` when getting
an user cache dir.
Expand Down Expand Up @@ -928,22 +933,18 @@ defmodule RustlerPrecompiled do
# Use HTTPS proxy auth if available, otherwise fall back to HTTP proxy auth
proxy_auth = https_proxy_auth || http_proxy_auth

# https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/inets
# respects the user provided ca certs via Hex env var
cacertfile = System.get_env("HEX_CACERTS_PATH", CAStore.file_path())

http_options =
[
ssl: [
verify: :verify_peer,
cacertfile: cacertfile |> String.to_charlist(),
# We need to increase depth because the default value is 1.
# See: https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/ssl
depth: 3,
customize_hostname_check: [
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
]
]
ssl:
[
verify: :verify_peer,
# We need to increase depth because the default value is 1.
# See: https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/ssl
depth: 3,
customize_hostname_check: [
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
]
] ++ cacerts_options()
]
|> maybe_add_proxy_auth(proxy_auth)

Expand Down Expand Up @@ -1031,6 +1032,53 @@ defmodule RustlerPrecompiled do
end
end

# https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/inets
defp cacerts_options do
cond do
path = System.get_env("HEX_CACERTS_PATH") ->
[cacertfile: path]

certs = otp_cacerts() ->
[cacerts: certs]

true ->
warn_no_cacerts()
[]
end
end

defp otp_cacerts do
if System.otp_release() >= "25" do
# cacerts_get/0 raises if no certs found
try do
:public_key.cacerts_get()
rescue
_ -> nil
end
end
end

defp warn_no_cacerts do
Logger.warning("""
No certificate trust store was found.

A certificate trust store is required in
order to download precompiled artifacts for
one of your system's library.
Since rustler_precompiled could not detect a system
installed certificate trust store, one of the
following actions may be taken:

1. Specify the location of a certificate trust store
by configuring it in environment variable:

export HEX_CACERTS_PATH="/path/to/cacerts.pem"

2. Use OTP 25+ on an OS that has built-in certificate
trust store.
""")
end

# Download a list of files from URLs and calculate its checksum.
# Returns a list with details of the download and the checksum of each file.
@doc false
Expand Down
6 changes: 3 additions & 3 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
defmodule RustlerPrecompiled.MixProject do
use Mix.Project

@version "0.8.4"
@version "0.9.0"
@repo "https://github.com/philss/rustler_precompiled"

def project do
[
app: :rustler_precompiled,
version: @version,
elixir: "~> 1.13",
elixir: "~> 1.15",
start_permanent: Mix.env() == :prod,
description: "Make the usage of precompiled NIFs easier for projects using Rustler",
package: package(),
test_ignore_filters: [&String.starts_with?(&1, "test/fixtures")],
docs: docs(),
deps: deps()
]
Expand All @@ -35,7 +36,6 @@ defmodule RustlerPrecompiled.MixProject do
defp deps do
[
{:rustler, "~> 0.23", optional: true},
{:castore, "~> 0.1 or ~> 1.0"},
{:ex_doc, "~> 0.27", only: :dev},
{:bypass, "~> 2.1", only: :test}
]
Expand Down
1 change: 0 additions & 1 deletion mix.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
%{
"bypass": {:hex, :bypass, "2.1.0", "909782781bf8e20ee86a9cabde36b259d44af8b9f38756173e8f5e2e1fabb9b1", [:mix], [{:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "d9b5df8fa5b7a6efa08384e9bbecfe4ce61c77d28a4282f79e02f1ef78d96b80"},
"castore": {:hex, :castore, "1.0.18", "5e43ef0ec7d31195dfa5a65a86e6131db999d074179d2ba5a8de11fe14570f55", [:mix], [], "hexpm", "f393e4fe6317829b158fb74d86eb681f737d2fe326aa61ccf6293c4104957e34"},
"cowboy": {:hex, :cowboy, "2.13.0", "09d770dd5f6a22cc60c071f432cd7cb87776164527f205c5a6b0f24ff6b38990", [:make, :rebar3], [{:cowlib, ">= 2.14.0 and < 3.0.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, ">= 1.8.0 and < 3.0.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "e724d3a70995025d654c1992c7b11dbfea95205c047d86ff9bf1cda92ddc5614"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
"cowlib": {:hex, :cowlib, "2.15.0", "3c97a318a933962d1c12b96ab7c1d728267d2c523c25a5b57b0f93392b6e9e25", [:make, :rebar3], [], "hexpm", "4f00c879a64b4fe7c8fcb42a4281925e9ffdb928820b03c3ad325a617e857532"},
Expand Down
Loading