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
11 changes: 10 additions & 1 deletion lib/hypatia/cli.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1202,7 +1202,7 @@ defmodule Hypatia.CLI do
# ─── Output formatting ───────────────────────────────────────────────

defp output(findings, "json") do
IO.puts(Jason.encode!(findings, pretty: true))
IO.puts(Jason.encode!(Enum.map(findings, &json_compat_severity/1), pretty: true))
end

defp output(findings, "sarif") do
Expand Down Expand Up @@ -1251,6 +1251,15 @@ defmodule Hypatia.CLI do
end
end

# Compatibility shim (standards#787 D260). Callers pinned to standards'
# hypatia-scan-reusable.yml before bd9313a6 validate the JSON against
# critical/high/medium/low/info and reject the whole array on one "warn",
# so ~350 repos failed with "Hypatia did not produce one valid findings
# array". warn already ranks with medium (@severity_order), so this loses
# no information. Remove once no caller is pinned to a rejecting copy.
defp json_compat_severity(%{severity: "warn"} = f), do: %{f | severity: "medium"}
defp json_compat_severity(f), do: f

defp output_report(findings, repo_path) do
IO.puts("=" |> String.duplicate(72))
IO.puts(" Hypatia Security & Policy Report")
Expand Down
34 changes: 34 additions & 0 deletions test/research_extensions_wiring_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,40 @@ defmodule Hypatia.Rules.ResearchExtensionsWiringTest do
assert summary =~ ~r/warn=[1-9][0-9]*/
end

# Callers on standards' hypatia-scan-reusable.yml before bd9313a6 reject
# the whole JSON array if any finding carries severity "warn" (D260).
test "CLI JSON output reports warn findings as medium, never as warn" do
repo = tripwire_repo()

json =
ExUnit.CaptureIO.capture_io(fn ->
ExUnit.CaptureIO.capture_io(:stderr, fn ->
CLI.main([
"scan",
repo,
"--rules",
"research_extensions",
"--format",
"json",
"--exit-zero"
])
end)
end)

findings = Jason.decode!(json)
severities = Enum.map(findings, & &1["severity"])

assert "medium" in severities,
"the tripwire repo emits warn-tier RE findings; none reached JSON"

refute "warn" in severities,
"a single \"warn\" makes every pre-bd9313a6 standards validator " <>
"reject the whole findings array"

allowed = ["critical", "high", "medium", "low", "info"]
assert Enum.all?(severities, &(&1 in allowed))
end

# Six of the ten RE rules emit `severity: :warn`. "warn" was absent from
# CLI's @severity_order, so `Map.get(@severity_order, "warn", 5)` gave it
# rank 5; the filter `rank <= threshold` at the default threshold of
Expand Down
Loading