From 444c86783599217620cb158f4e24a7885f11f6a6 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 14 Nov 2026 19:38:45 +0000 Subject: [PATCH] fix(coverage): keep unknown evidence tag keys as strings EvidenceFormatter turned every string key of an `@tag evidence:` map into an atom with String.to_atom/1. Hypatia's own code_safety rule flags this (elixir_atom_from_user, high), and since #1107 merged it has turned the "Validate Hypatia Baseline" gate red on every open PR. Keys the formatter reads already exist as atoms, so String.to_existing_atom/1 keeps them; any other key stays a string. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0136P7ZkGCWGEyedTtdEHAPT --- lib/hypatia/coverage/evidence_formatter.ex | 9 ++++++++- test/coverage/evidence_formatter_test.exs | 9 +++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/hypatia/coverage/evidence_formatter.ex b/lib/hypatia/coverage/evidence_formatter.ex index ed914cee..5091031b 100644 --- a/lib/hypatia/coverage/evidence_formatter.ex +++ b/lib/hypatia/coverage/evidence_formatter.ex @@ -194,7 +194,14 @@ defmodule Hypatia.Coverage.EvidenceFormatter do defp evidence_tag(_), do: %{} defp to_key(k) when is_atom(k), do: k - defp to_key(k) when is_binary(k), do: String.to_atom(k) + # Only keys the formatter reads exist as atoms; any other string key stays a string, + # so a tag cannot grow the atom table. + defp to_key(k) when is_binary(k) do + String.to_existing_atom(k) + rescue + ArgumentError -> k + end + defp to_key(k), do: k defp kind(tag) do diff --git a/test/coverage/evidence_formatter_test.exs b/test/coverage/evidence_formatter_test.exs index 51ec803d..84626be6 100644 --- a/test/coverage/evidence_formatter_test.exs +++ b/test/coverage/evidence_formatter_test.exs @@ -122,6 +122,15 @@ defmodule Hypatia.Coverage.EvidenceFormatterTest do assert counted?(r) == :counted end + # Hypatia code_safety/elixir_atom_from_user on main after #1107. + test "an unknown string key in the tag does not create an atom" do + key = "zz_evidence_key_#{System.unique_integer([:positive])}" + tag = %{evidence: %{"kind" => "E", key => 1}} + r = EvidenceFormatter.record(test_struct(:"test atom", nil, tag), @cfg) + assert r["kind"] == "E" + assert_raise ArgumentError, fn -> String.to_existing_atom(key) end + end + test "a nested property map and string keys work the same" do tag = %{ "kind" => "R",