Compare commits

...
10 Commits
Author SHA1 Message Date
José Valim dfe6612e54 Release v1.18.5 2026-08-28 12:19:42 +02:00
José Valim 5230d73968 Fix recursion on charlist error path 2026-08-28 12:18:24 +02:00
sabiwara ef36b163b3 Add potential breaking change for unquote to changelog 2026-06-13 23:29:52 +09:00
Jonatan Männchen a622a8ef92 Correct builds.hex.pm Publish Condition in CI (#14772) 2025-09-15 23:15:03 +02:00
Jonatan Männchen 66bb6da847 Fix backport of workload identity & CI release scope (#14745)
Backported PRs:
* https://github.com/elixir-lang/elixir/pull/14604
* https://github.com/elixir-lang/elixir/pull/14627

The commits are based on the SBoM PR (#14241) which changed the
actions.
2025-09-05 09:12:16 +02:00
Jonatan Männchen eee55adcd0 Use Workload Identity Federation for Windows Trusted Signing (#14604) 2025-09-03 22:31:31 +02:00
Jonatan Männchen cbd5ffce3e tighten CI secret scope and move AWS config to environment vars (#14627)
* Add `environment: release` to the "publish-to-hex" job so that only
  workflows explicitly targeting the release environment can read
  sensitive values.
* Gate the job behind `if: ${{ vars.HEX_AWS_REGION }}` to avoid noisy
  failures in forks where the variable is not configured.
* Replace `${{ secrets.HEX_AWS_REGION }}` / `${{ secrets.HEX_AWS_S3_BUCKET }}`
  references with `${{ vars.* }}`.  These are not credentials, so
  environment-level *variables* are a better fit and keep them readable
  only by jobs that declare the environment.
* Remove Fastly secrets from the job-wide `env:` block and inject them
  only into the Fastly purge step, following the principle of least
  privilege.  Other steps no longer see these tokens.

Restricting secret visibility to an environment and to the exact step
that needs them reduces the blast radius of a compromised workflow run,
blocks accidental exposure in logs of unrelated steps, and stops forks
from obtaining privileged data.
2025-09-03 22:16:28 +02:00
José Valim a3dda22035 Do not mention OTP 28 yet on v1.18 2025-07-22 11:55:07 +02:00
José Valim 7184679788 Reduce filesystem names on Mix.install, see #14543 2025-05-29 17:17:00 +02:00
José Valim aeb2ea1dda Clarify regexes in OTP 28 2025-05-21 15:50:59 +02:00
12 changed files with 117 additions and 29 deletions
+30 -12
View File
@@ -118,6 +118,7 @@ jobs:
sign:
needs: [build]
environment: release
strategy:
fail-fast: true
matrix:
@@ -129,21 +130,30 @@ jobs:
runs-on: ${{ matrix.flavor == 'linux' && 'ubuntu-22.04' || 'windows-2022' }}
permissions:
contents: write
id-token: write
attestations: write
steps:
- uses: actions/download-artifact@v4
with:
name: build-${{ matrix.flavor }}-elixir-otp-${{ matrix.otp }}
- name: Log in to Azure
if: ${{ matrix.flavor == 'windows' && vars.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}
uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2.3.0
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: "Sign files with Trusted Signing"
if: github.repository == 'elixir-lang/elixir' && matrix.flavor == 'windows'
uses: azure/trusted-signing-action@v0.5.0
uses: azure/trusted-signing-action@0d74250c661747df006298d0fb49944c10f16e03 # v0.5.1
if: ${{ matrix.flavor == 'windows' && vars.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}
with:
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
endpoint: https://eus.codesigning.azure.net/
trusted-signing-account-name: trusted-signing-elixir
certificate-profile-name: Elixir
trusted-signing-account-name: ${{ vars.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}
certificate-profile-name: ${{ vars.AZURE_CERTIFICATE_PROFILE_NAME }}
files-folder: ${{ github.workspace }}
files-folder-filter: exe
file-digest: SHA256
@@ -223,16 +233,20 @@ jobs:
needs: [build, sign]
runs-on: ubuntu-22.04
concurrency: builds-hex-pm
environment: release
env:
AWS_ACCESS_KEY_ID: ${{ secrets.HEX_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.HEX_AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.HEX_AWS_REGION }}
AWS_S3_BUCKET: ${{ secrets.HEX_AWS_S3_BUCKET }}
FASTLY_REPO_SERVICE_ID: ${{ secrets.HEX_FASTLY_REPO_SERVICE_ID }}
FASTLY_BUILDS_SERVICE_ID: ${{ secrets.HEX_FASTLY_BUILDS_SERVICE_ID }}
FASTLY_KEY: ${{ secrets.HEX_FASTLY_KEY }}
AWS_REGION: ${{ vars.HEX_AWS_REGION }}
AWS_S3_BUCKET: ${{ vars.HEX_AWS_S3_BUCKET }}
OTP_GENERIC_VERSION: "25"
steps:
- name: "Check if variables are set up"
if: "${{ ! vars.HEX_AWS_REGION }}"
run: |
echo "Required variables for uploading to hex.pm are not set up, skipping..."
exit 1
- uses: actions/download-artifact@v4
with:
pattern: "{sign-*-elixir-otp-*,Docs}"
@@ -337,3 +351,7 @@ jobs:
for key in $(cat purge_keys.txt); do
purge "${key}"
done
env:
FASTLY_REPO_SERVICE_ID: ${{ secrets.HEX_FASTLY_REPO_SERVICE_ID }}
FASTLY_BUILDS_SERVICE_ID: ${{ secrets.HEX_FASTLY_BUILDS_SERVICE_ID }}
FASTLY_KEY: ${{ secrets.HEX_FASTLY_KEY }}
+24 -1
View File
@@ -223,9 +223,26 @@ You may also prefer to write using guards:
def foo(x, y, z) when x == y and y == z
## v1.18.5 (2026-08-28)
### 1. Security
* [List] Avoid recursion when invalid charlists are given to `List.to_string/1` or `List.to_charlist/1` (CVE-2026-75758, GHSA-jf5q-v438-665c)
## v1.18.4 (2025-05-21)
This release includes initial support for Erlang/OTP 28, for those who want to try it out. In such cases, you may use Elixir v1.18.4 precompiled for Erlang/OTP 27, as it is binary compatible with Erlang/OTP 28.
This release includes initial support for Erlang/OTP 28, for those who want to try it out. In such cases, you may use Elixir v1.18.4 precompiled for Erlang/OTP 27, as it is binary compatible with Erlang/OTP 28. Note, however, that Erlang/OTP 28 no longer allows regexes to be defined in the module body and interpolated into an attribute. If you do this:
```elixir
@some_attribute ~r/foo/
def some_fun, do: @some_attribute
```
You must rewrite it to:
```elixir
def some_fun, do: ~r/foo/
```
### 1. Enhancements
@@ -477,6 +494,12 @@ This release includes initial support for Erlang/OTP 28, for those who want to t
* [mix test] `:warnings_as_errors` configuration in `:test_elixirc_options` is deprecated. Instead pass the `--warnings-as-errors` flag to `mix test`. Alternatively, you might alias the task: `aliases: [test: "test --warnings-as-errors"]`
* [Mix.Tasks.Compile] Deprecate `compilers/0` in favor of `Mix.Task.Compiler.compilers/0`
### 5. Potential breaking changes
#### Elixir
* [Kernel] Using unquote is deprecated when quote is used inside a pattern or guard
## v1.17
The CHANGELOG for v1.17 releases can be found [in the v1.17 branch](https://github.com/elixir-lang/elixir/blob/v1.17/CHANGELOG.md).
+1 -1
View File
@@ -1 +1 @@
1.18.4
1.18.5
+1 -1
View File
@@ -1,7 +1,7 @@
#!/bin/sh
set -e
ELIXIR_VERSION=1.18.4
ELIXIR_VERSION=1.18.5
if [ $# -eq 0 ] || { [ $# -eq 1 ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; }; then
cat <<USAGE >&2
+1 -1
View File
@@ -1,6 +1,6 @@
@echo off
set ELIXIR_VERSION=1.18.4
set ELIXIR_VERSION=1.18.5
if ""%1""=="""" if ""%2""=="""" goto documentation
if /I ""%1""==""--help"" if ""%2""=="""" goto documentation
+25 -5
View File
@@ -343,13 +343,20 @@ defimpl Inspect, for: List do
close = color_doc("]", :list, opts)
cond do
lists == :as_charlists or (lists == :infer and List.ascii_printable?(term, printable_limit)) ->
inspected =
case Identifier.escape(IO.chardata_to_string(term), ?", printable_limit) do
{escaped, ""} -> [?~, ?c, ?", escaped, ?"]
{escaped, _} -> [?~, ?c, ?", escaped, ?", " ++ ..."]
(lists == :as_charlists and unicode_list?(term, printable_limit)) or
(lists == :infer and List.ascii_printable?(term, printable_limit)) ->
{split, tail} =
if is_integer(printable_limit) do
case Enum.split(term, printable_limit) do
{split, []} -> {split, []}
{split, _} -> {split, " ++ ..."}
end
else
{term, []}
end
{escaped, _} = Identifier.escape(IO.chardata_to_string(split), ?")
inspected = [?~, ?c, ?", escaped, ?" | tail]
color_doc(IO.iodata_to_binary(inspected), :charlist, opts)
keyword?(term) ->
@@ -360,6 +367,19 @@ defimpl Inspect, for: List do
end
end
defp unicode_list?(_, 0), do: true
defp unicode_list?([char | rest], counter)
when char in 0..0xD7FF or char in 0xE000..0x10FFFF,
do: unicode_list?(rest, decrement(counter))
defp unicode_list?([], _counter), do: true
defp unicode_list?(_, _counter), do: false
@compile {:inline, decrement: 1}
defp decrement(:infinity), do: :infinity
defp decrement(counter), do: counter - 1
@doc false
def keyword({key, value}, opts) do
key = color_doc(Macro.inspect_atom(:key, key), :atom, opts)
+2 -2
View File
@@ -17,8 +17,8 @@ defmodule Inspect.Opts do
is `:decimal` and if it is printable, otherwise in bit syntax. See
`String.printable?/1` to learn when a string is printable.
* `:charlists` - when `:as_charlists` all lists will be printed as charlists,
non-printable elements will be escaped.
* `:charlists` - when `:as_charlists` all charlists will be printed as charlists,
non-printable code points will be escaped. Other lists will be printed as lists.
When `:as_lists` all lists will be printed as lists.
+2 -2
View File
@@ -1133,7 +1133,7 @@ defmodule List do
Please check the given list or call inspect/1 to get the list representation, got:
#{inspect(list)}
#{inspect(list, charlists: :as_lists)}
"""
else
result when is_binary(result) ->
@@ -1185,7 +1185,7 @@ defmodule List do
Please check the given list or call inspect/1 to get the list representation, got:
#{inspect(list)}
#{inspect(list, charlists: :as_lists)}
"""
else
result when is_list(result) ->
@@ -42,7 +42,7 @@ Erlang/OTP versioning is independent from the versioning of Elixir. Erlang relea
Elixir version | Supported Erlang/OTP versions
:------------- | :-------------------------------
1.18 | 25 - 27 (and Erlang/OTP 28 from v1.18.4)
1.18 | 25 - 27
1.17 | 25 - 27
1.16 | 24 - 26
1.15 | 24 - 26
+16 -1
View File
@@ -278,10 +278,15 @@ defmodule Inspect.ListTest do
test "printable limit" do
assert inspect(~c"hello world", printable_limit: 4) == ~s(~c"hell" ++ ...)
assert inspect(~c"hello", printable_limit: :infinity) == ~s(~c"hello")
# Non printable characters after the limit don't matter
assert inspect(~c"hello world" ++ [0], printable_limit: 4) == ~s(~c"hell" ++ ...)
# Non printable strings aren't affected by printable limit
assert inspect([0, 1, 2, 3, 4], printable_limit: 3) == ~s([0, 1, 2, 3, 4])
# Ensure a non-printable value after limit does not crash
assert inspect(~c"hello world" ++ [nil], printable_limit: 4) == ~s(~c"hell" ++ ...)
# Ensure a non-printable value after default limit does not hang
assert String.ends_with?(inspect(List.duplicate(?a, 5000) ++ [nil]), "\" ++ ...")
end
test "keyword" do
@@ -306,10 +311,20 @@ defmodule Inspect.ListTest do
assert inspect([0], charlists: :infer) == "[0]"
end
test "opt as strings" do
test "opt as charlists" do
assert inspect(~c"john" ++ [0] ++ ~c"doe", charlists: :as_charlists) == ~s(~c"john\\0doe")
assert inspect(~c"john", charlists: :as_charlists) == ~s(~c"john")
assert inspect([0], charlists: :as_charlists) == ~s(~c"\\0")
assert inspect([nil], charlists: :as_charlists) == "[nil]"
assert inspect([0xD800], charlists: :as_charlists) == "[55296]"
assert inspect([1_114_112], charlists: :as_charlists) == "[1114112]"
assert inspect([[?a]], charlists: :as_charlists) == ~s([~c"a"])
assert inspect([?a, ?b, ?c | nil], charlists: :as_charlists, printable_limit: 4) ==
"[97, 98, 99 | nil]"
assert inspect([?a, ?b, ?c | nil], charlists: :as_charlists, printable_limit: 3) ==
~s(~c"abc" ++ ...)
end
test "opt as lists" do
+12
View File
@@ -327,6 +327,12 @@ defmodule ListTest do
assert_raise ArgumentError, ~r"cannot convert the given list to a string", fn ->
List.to_string([:a, :b])
end
invalid = List.duplicate(?a, 4096) ++ [nil]
assert_raise ArgumentError, ~r/got:\n\n\[97, 97, .*\.\.\.\]\n\z/s, fn ->
List.to_string(invalid)
end
end
test "to_charlist/1" do
@@ -345,6 +351,12 @@ defmodule ListTest do
assert_raise ArgumentError, ~r"cannot convert the given list to a charlist", fn ->
List.to_charlist([:a, :b])
end
invalid = List.duplicate(?a, 4096) ++ [nil]
assert_raise ArgumentError, ~r/got:\n\n\[97, 97, .*\.\.\.\]\n\z/s, fn ->
List.to_charlist(invalid)
end
end
describe "myers_difference/2" do
+2 -2
View File
@@ -894,7 +894,7 @@ defmodule Mix do
{deps, config, system_env, consolidate_protocols?}
|> :erlang.term_to_binary()
|> :erlang.md5()
|> Base.encode16(case: :lower)
|> Base.url_encode64(case: :lower, padding: false)
force? = System.get_env("MIX_INSTALL_FORCE") in ["1", "true"] or Keyword.fetch!(opts, :force)
@@ -1068,7 +1068,7 @@ defmodule Mix do
System.get_env("MIX_INSTALL_DIR") ||
Path.join(Mix.Utils.mix_cache(), "installs")
version = "elixir-#{System.version()}-erts-#{:erlang.system_info(:version)}"
version = "ex-#{System.version()}-erl-#{:erlang.system_info(:version)}"
Path.join([install_root, version, cache_id])
end