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
40 changes: 33 additions & 7 deletions lib/mix/tasks/hex.policy.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,14 @@ defmodule Mix.Tasks.Hex.Policy do
Shows the active Hex policy and explains why specific versions
are blocked.

$ mix hex.policy
$ mix hex.policy show
$ mix hex.policy why PACKAGE

## Commands

* `show` — Summarize the active policy: visibility and the
per-repository restrictions (cooldown, advisory, retirement) and
override counts, plus the effective cooldown. This is the default
when no command is given.
the package overrides, plus the effective cooldown.
* `why PACKAGE` — Walk every version of the named package in the
registry, classify each against the active policy, and print a
per-version table of status and the reasons it is blocked.
Expand Down Expand Up @@ -55,9 +53,6 @@ defmodule Mix.Tasks.Hex.Policy do
Hex.start()

case args do
[] ->
show()

["show"] ->
show()

Expand Down Expand Up @@ -137,9 +132,40 @@ defmodule Mix.Tasks.Hex.Policy do
Hex.Shell.info([" Cooldown: ", cooldown_label(restriction)])
Hex.Shell.info([" Advisory rule: ", advisory_label(restriction)])
Hex.Shell.info([" Retirement rule: ", retirement_label(restriction)])
Hex.Shell.info([" Overrides: ", to_string(length(overrides))])
render_overrides(overrides)
end

defp render_overrides([]) do
Hex.Shell.info([" Overrides: ", [:faint, "(none)"]])
end

defp render_overrides(overrides) do
Hex.Shell.info([" Overrides:"])

Enum.each(overrides, fn override ->
Hex.Shell.info([" ", override_label(override)])
end)
end

defp override_label(%{action: action, ref: ref}) do
package = Map.get(ref, :package)

package_text =
case Map.get(ref, :requirement) do
requirement when is_binary(requirement) and requirement != "" ->
"#{package} #{requirement}"

_ ->
"#{package}"
end

[package_text, " ", override_action_label(action)]
end

defp override_action_label(:OVERRIDE_ACTION_ALLOW), do: [:green, "ALLOW"]
defp override_action_label(:OVERRIDE_ACTION_DENY), do: [:red, "DENY"]
defp override_action_label(other), do: [to_string(other)]

defp why(arg) do
{repo, package} = parse_package_arg(arg)

Expand Down
47 changes: 44 additions & 3 deletions test/mix/tasks/hex.policy_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,54 @@ defmodule Mix.Tasks.Hex.PolicyTest do
assert out =~ "HIGH"
end

test "a bare invocation (no subcommand) defaults to show" do
out = capture_io(fn -> Mix.Tasks.Hex.Policy.run([]) end)
assert out =~ "No active policy"
test "lists each package override with its action" do
Hex.State.put(:active_policy, %{
repository: "myorg",
name: "strict-prod",
visibility: :VISIBILITY_PUBLIC,
repositories: [
%{
repository: "hexpm",
restriction: %{},
overrides: [
%{action: :OVERRIDE_ACTION_ALLOW, ref: %{package: "plug", requirement: ">= 1.0.0"}},
%{action: :OVERRIDE_ACTION_DENY, ref: %{package: "evil_dep"}}
]
}
]
})

out = capture_io(fn -> Mix.Tasks.Hex.Policy.run(["show"]) end)
assert out =~ "plug"
assert out =~ ">= 1.0.0"
assert out =~ "ALLOW"
assert out =~ "evil_dep"
assert out =~ "DENY"
end

test "renders a (none) placeholder when a repository has no overrides" do
Hex.State.put(:active_policy, %{
repository: "myorg",
name: "strict-prod",
visibility: :VISIBILITY_PUBLIC,
repositories: [
%{repository: "hexpm", restriction: %{}, overrides: []}
]
})

out = capture_io(fn -> Mix.Tasks.Hex.Policy.run(["show"]) end)
assert out =~ "Overrides:"
assert out =~ "(none)"
end
end

describe "why" do
test "a bare invocation (no subcommand) raises the usage message" do
assert_raise Mix.Error, ~r/Invalid arguments, expected one of:/, fn ->
Mix.Tasks.Hex.Policy.run([])
end
end

test "complains when package name is missing" do
assert_raise Mix.Error, ~r/Invalid arguments, expected one of:/, fn ->
Mix.Tasks.Hex.Policy.run(["why"])
Expand Down
Loading