From 137079beef19b646dc49e1e8aee7b03ad56f673a Mon Sep 17 00:00:00 2001 From: Taras Tyshko Date: Thu, 7 Aug 2025 10:53:35 +0300 Subject: [PATCH 01/13] Add unitest for Audit Logs pagination at Device page --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4eecc6282..d7217e10f 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,6 @@ test/fixtures/ssl/device-root-ca.srl .elixir-tools .DS_Store -/cover/ \ No newline at end of file +.idea/ +/cover/ +nerves_hub.iml \ No newline at end of file From e0da1056b6cebd60f726fe4d6a9ae90da4483bd2 Mon Sep 17 00:00:00 2001 From: Taras Tyshko Date: Fri, 8 Aug 2025 13:17:44 +0300 Subject: [PATCH 02/13] optimize pagination logic and use ~p sigil in tests --- .gitignore | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index d7217e10f..22780a484 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,4 @@ test/fixtures/ssl/device-root-ca.srl .lexical .elixir-tools -.DS_Store -.idea/ -/cover/ -nerves_hub.iml \ No newline at end of file +.DS_Store \ No newline at end of file From 392849ed0344ec44c9fd8c4c99ccdc206c36039e Mon Sep 17 00:00:00 2001 From: Taras Tyshko Date: Fri, 8 Aug 2025 13:27:51 +0300 Subject: [PATCH 03/13] revert .gitignore and some part of code --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 22780a484..4eecc6282 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,5 @@ test/fixtures/ssl/device-root-ca.srl .lexical .elixir-tools -.DS_Store \ No newline at end of file +.DS_Store +/cover/ \ No newline at end of file From 64fd99715195827e3058a7c59cac9a441163b93c Mon Sep 17 00:00:00 2001 From: Taras Tyshko Date: Thu, 7 Aug 2025 20:17:50 +0300 Subject: [PATCH 04/13] Refactor complex macros and enforce Credo in CI --- .credo.exs | 15 +++--- .github/workflows/ci.yml | 4 +- lib/nerves_hub/accounts.ex | 3 +- lib/nerves_hub/accounts/user_notifier.ex | 5 +- lib/nerves_hub/application.ex | 5 +- lib/nerves_hub/certificate.ex | 6 ++- lib/nerves_hub/device_ssl_transport.ex | 40 ++++++++-------- lib/nerves_hub/devices.ex | 38 +++++---------- lib/nerves_hub/devices/log_lines.ex | 10 ++-- lib/nerves_hub/emails/closing_block.ex | 6 ++- lib/nerves_hub/extensions.ex | 13 ++---- lib/nerves_hub/extensions/geo.ex | 12 ++--- lib/nerves_hub/extensions/health.ex | 4 +- lib/nerves_hub/tracker.ex | 44 +++++------------- .../components/core_components.ex | 6 +-- .../components/device_update_status.ex | 46 +++++++------------ .../api/openapi/device_controller_specs.ex | 2 +- .../controllers/session_controller.ex | 2 +- .../dynamic_config_multipart.ex | 6 ++- .../live/deployment_groups/index.ex | 2 +- lib/nerves_hub_web/plugs/configure_uploads.ex | 6 ++- lib/nerves_hub_web/plugs/im_alive.ex | 3 +- lib/nerves_hub_web/views/layout_view.ex | 3 +- test/nerves_hub/devices_test.exs | 33 +++---------- test/nerves_hub/firmwares_test.exs | 2 +- test/nerves_hub/ssl_test.exs | 3 +- .../device_events_stream_channel_test.exs | 4 +- .../channels/websocket_test.exs | 17 +++---- .../live/new_ui/devices/logs_tab_test.exs | 2 +- .../live/new_ui/devices/settings_tab_test.exs | 2 +- test/nerves_hub_web/plugs/org_user_test.exs | 7 +-- .../views/api/error_view_test.exs | 16 +++---- test/support/channel_case.ex | 14 +++--- test/support/conn_case.ex | 15 ++++-- test/support/data_case.ex | 10 ++-- test/support/fixtures.ex | 36 ++++++--------- test/support/utils.ex | 3 +- 37 files changed, 188 insertions(+), 257 deletions(-) diff --git a/.credo.exs b/.credo.exs index 33ee9d429..02f69088f 100644 --- a/.credo.exs +++ b/.credo.exs @@ -84,12 +84,6 @@ {Credo.Check.Design.AliasUsage, [priority: :low, if_nested_deeper_than: 2, if_called_more_often_than: 0]}, {Credo.Check.Design.TagFIXME, []}, - # You can also customize the exit_status of each check. - # If you don't want TODO comments to cause `mix credo` to fail, just - # set this value to 0 (zero). - # - {Credo.Check.Design.TagTODO, [exit_status: 0]}, - # ## Readability Checks # @@ -99,7 +93,6 @@ {Credo.Check.Readability.LargeNumbers, []}, {Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 120]}, {Credo.Check.Readability.ModuleAttributeNames, []}, - {Credo.Check.Readability.ModuleDoc, []}, {Credo.Check.Readability.ModuleNames, []}, {Credo.Check.Readability.MultiAlias, []}, {Credo.Check.Readability.ParenthesesInCondition, []}, @@ -170,6 +163,14 @@ {Credo.Check.Warning.WrongTestFileExtension, []} ], disabled: [ + # + # TODO comments are acceptable in our codebase + {Credo.Check.Design.TagTODO, []}, + + # + # ModuleDoc is not required in our codebase + {Credo.Check.Readability.ModuleDoc, []}, + # # Checks scheduled for next check update (opt-in for now) {Credo.Check.Refactor.UtcNowTruncate, []}, diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bbad281bd..172d36918 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -112,8 +112,8 @@ jobs: - name: Check spelling run: mix spellweaver.check - - name: Run Credo (won't fail the build) - run: mix credo --mute-exit-status + - name: Run Credo + run: mix credo - name: DB Setup run: mix ecto.migrate.reset diff --git a/lib/nerves_hub/accounts.ex b/lib/nerves_hub/accounts.ex index cbeed4c0a..a67594368 100644 --- a/lib/nerves_hub/accounts.ex +++ b/lib/nerves_hub/accounts.ex @@ -3,7 +3,6 @@ defmodule NervesHub.Accounts do alias Ecto.Changeset alias Ecto.Multi - alias NervesHub.Accounts.Invite alias NervesHub.Accounts.Org alias NervesHub.Accounts.OrgKey @@ -11,11 +10,11 @@ defmodule NervesHub.Accounts do alias NervesHub.Accounts.OrgUser alias NervesHub.Accounts.RemoveAccount alias NervesHub.Accounts.User + alias NervesHub.Accounts.UserNotifier alias NervesHub.Accounts.UserToken alias NervesHub.Devices alias NervesHub.Devices.Device alias NervesHub.Products.Product - alias NervesHub.Accounts.UserNotifier alias NervesHub.Repo diff --git a/lib/nerves_hub/accounts/user_notifier.ex b/lib/nerves_hub/accounts/user_notifier.ex index d781c0b7e..e1103aa1b 100644 --- a/lib/nerves_hub/accounts/user_notifier.ex +++ b/lib/nerves_hub/accounts/user_notifier.ex @@ -7,8 +7,8 @@ defmodule NervesHub.Accounts.UserNotifier do alias NervesHub.Emails.ConfirmationTemplate alias NervesHub.Emails.LoginWithGoogleReminderTemplate alias NervesHub.Emails.OrgUserAddedTemplate - alias NervesHub.Emails.PasswordResetTemplate alias NervesHub.Emails.PasswordResetConfirmationTemplate + alias NervesHub.Emails.PasswordResetTemplate alias NervesHub.Emails.PasswordUpdatedTemplate alias NervesHub.Emails.TellOrgUserAddedTemplate alias NervesHub.Emails.TellOrgUserInvitedTemplate @@ -17,6 +17,7 @@ defmodule NervesHub.Accounts.UserNotifier do alias NervesHub.Emails.WelcomeTemplate alias NervesHub.SwooshMailer, as: Mailer + alias Phoenix.HTML def deliver_confirmation_instructions(user, confirmation_url) do assigns = %{ @@ -207,7 +208,7 @@ defmodule NervesHub.Accounts.UserNotifier do text = module.text_render(assigns) - |> Phoenix.HTML.Safe.to_iodata() + |> HTML.Safe.to_iodata() |> IO.iodata_to_binary() {html, text} diff --git a/lib/nerves_hub/application.ex b/lib/nerves_hub/application.ex index 44c293af7..fead89d44 100644 --- a/lib/nerves_hub/application.ex +++ b/lib/nerves_hub/application.ex @@ -1,7 +1,7 @@ defmodule NervesHub.Application do use Application - require Logger + alias NervesHub.Telemetry.Customizations def start(_type, _args) do case System.cmd("fwup", ["--version"], env: []) do @@ -57,8 +57,7 @@ defmodule NervesHub.Application do :ok = :httpc.set_option(:ipfamily, :inet6fb4) end - :ok = NervesHub.Telemetry.Customizations.setup() - + :ok = Customizations.setup() :ok = OpentelemetryBandit.setup() :ok = OpentelemetryPhoenix.setup(adapter: :bandit) :ok = OpentelemetryOban.setup(trace: [:jobs]) diff --git a/lib/nerves_hub/certificate.ex b/lib/nerves_hub/certificate.ex index 7018c6f91..85761bc4c 100644 --- a/lib/nerves_hub/certificate.ex +++ b/lib/nerves_hub/certificate.ex @@ -1,4 +1,6 @@ defmodule NervesHub.Certificate do + alias X509.Certificate.Extension + import X509.ASN1, only: [ extension: 1, @@ -17,7 +19,7 @@ defmodule NervesHub.Certificate do def get_aki(otp_certificate) do otp_certificate |> X509.Certificate.extensions() - |> X509.Certificate.Extension.find(:authority_key_identifier) + |> Extension.find(:authority_key_identifier) |> extension() |> Keyword.get(:extnValue) |> authority_key_identifier() @@ -27,7 +29,7 @@ defmodule NervesHub.Certificate do def get_ski(otp_certificate) do otp_certificate |> X509.Certificate.extensions() - |> X509.Certificate.Extension.find(:subject_key_identifier) + |> Extension.find(:subject_key_identifier) |> case do nil -> nil diff --git a/lib/nerves_hub/device_ssl_transport.ex b/lib/nerves_hub/device_ssl_transport.ex index b321d4d25..9aeadea1f 100644 --- a/lib/nerves_hub/device_ssl_transport.ex +++ b/lib/nerves_hub/device_ssl_transport.ex @@ -13,18 +13,20 @@ defmodule NervesHub.DeviceSSLTransport do @behaviour ThousandIsland.Transport + alias ThousandIsland.Transports.SSL + @impl ThousandIsland.Transport - defdelegate listen(port, user_options), to: ThousandIsland.Transports.SSL + defdelegate listen(port, user_options), to: SSL @impl ThousandIsland.Transport - defdelegate accept(listener_socket), to: ThousandIsland.Transports.SSL + defdelegate accept(listener_socket), to: SSL @impl ThousandIsland.Transport def handshake(socket) do if NervesHub.RateLimit.increment() do :telemetry.execute([:nerves_hub, :rate_limit, :accepted], %{count: 1}) - ThousandIsland.Transports.SSL.handshake(socket) + SSL.handshake(socket) else :telemetry.execute([:nerves_hub, :rate_limit, :rejected], %{count: 1}) @@ -33,50 +35,50 @@ defmodule NervesHub.DeviceSSLTransport do end @impl ThousandIsland.Transport - defdelegate upgrade(socket, opts), to: ThousandIsland.Transports.SSL + defdelegate upgrade(socket, opts), to: SSL @impl ThousandIsland.Transport - defdelegate controlling_process(socket, pid), to: ThousandIsland.Transports.SSL + defdelegate controlling_process(socket, pid), to: SSL @impl ThousandIsland.Transport - defdelegate recv(socket, length, timeout), to: ThousandIsland.Transports.SSL + defdelegate recv(socket, length, timeout), to: SSL @impl ThousandIsland.Transport - defdelegate send(socket, data), to: ThousandIsland.Transports.SSL + defdelegate send(socket, data), to: SSL @impl ThousandIsland.Transport - defdelegate sendfile(socket, filename, offset, length), to: ThousandIsland.Transports.SSL + defdelegate sendfile(socket, filename, offset, length), to: SSL @impl ThousandIsland.Transport - defdelegate getopts(socket, options), to: ThousandIsland.Transports.SSL + defdelegate getopts(socket, options), to: SSL @impl ThousandIsland.Transport - defdelegate setopts(socket, options), to: ThousandIsland.Transports.SSL + defdelegate setopts(socket, options), to: SSL @impl ThousandIsland.Transport - defdelegate shutdown(socket, way), to: ThousandIsland.Transports.SSL + defdelegate shutdown(socket, way), to: SSL @impl ThousandIsland.Transport - defdelegate close(socket), to: ThousandIsland.Transports.SSL + defdelegate close(socket), to: SSL @impl ThousandIsland.Transport - defdelegate sockname(socket), to: ThousandIsland.Transports.SSL + defdelegate sockname(socket), to: SSL @impl ThousandIsland.Transport - defdelegate peername(socket), to: ThousandIsland.Transports.SSL + defdelegate peername(socket), to: SSL @impl ThousandIsland.Transport - defdelegate peercert(socket), to: ThousandIsland.Transports.SSL + defdelegate peercert(socket), to: SSL @impl ThousandIsland.Transport - defdelegate secure?(), to: ThousandIsland.Transports.SSL + defdelegate secure?(), to: SSL @impl ThousandIsland.Transport - defdelegate getstat(socket), to: ThousandIsland.Transports.SSL + defdelegate getstat(socket), to: SSL @impl ThousandIsland.Transport - defdelegate negotiated_protocol(socket), to: ThousandIsland.Transports.SSL + defdelegate negotiated_protocol(socket), to: SSL @impl ThousandIsland.Transport - defdelegate connection_information(socket), to: ThousandIsland.Transports.SSL + defdelegate connection_information(socket), to: SSL end diff --git a/lib/nerves_hub/devices.ex b/lib/nerves_hub/devices.ex index 9ff40def5..55ee97bd1 100644 --- a/lib/nerves_hub/devices.ex +++ b/lib/nerves_hub/devices.ex @@ -37,6 +37,7 @@ defmodule NervesHub.Devices do alias NervesHub.Products.Product alias NervesHub.Repo alias NervesHub.TaskSupervisor, as: Tasks + alias Phoenix.Channel.Server, as: ChannelServer def get_device(device_id) when is_integer(device_id) do Repo.get(Device, device_id) @@ -668,13 +669,9 @@ defmodule NervesHub.Devices do {:ok, device} = update_device(device, %{firmware_validation_status: "validated"}) - Phoenix.Channel.Server.broadcast_from!( - NervesHub.PubSub, - self(), - "device:#{device.identifier}:internal", - "firmware:validated", - %{} - ) + event = "firmware:validated" + topic = "device:#{device.identifier}:internal" + ChannelServer.broadcast_from!(NervesHub.PubSub, self(), topic, event, %{}) {:ok, device} end @@ -1021,13 +1018,8 @@ defmodule NervesHub.Devices do firmware_uuid: firmware_uuid } - _ = - Phoenix.Channel.Server.broadcast( - NervesHub.PubSub, - "orchestrator:deployment:#{device.deployment_id}", - "device-online", - payload - ) + topic = "orchestrator:deployment:#{device.deployment_id}" + _ = ChannelServer.broadcast(NervesHub.PubSub, topic, "device-online", payload) :ok end @@ -1037,13 +1029,8 @@ defmodule NervesHub.Devices do end def deployment_device_updated(device) do - _ = - Phoenix.Channel.Server.broadcast( - NervesHub.PubSub, - "orchestrator:deployment:#{device.deployment_id}", - "device-updated", - %{} - ) + topic = "orchestrator:deployment:#{device.deployment_id}" + _ = ChannelServer.broadcast(NervesHub.PubSub, topic, "device-updated", %{}) :ok end @@ -1185,12 +1172,9 @@ defmodule NervesHub.Devices do {:ok, device} = result -> _ = if device.deployment_id do - Phoenix.Channel.Server.broadcast( - NervesHub.PubSub, - "orchestrator:deployment:#{device.deployment_id}", - "device-updated", - %{} - ) + event = "device-updated" + topic = "orchestrator:deployment:#{device.deployment_id}" + ChannelServer.broadcast(NervesHub.PubSub, topic, event, %{}) end result diff --git a/lib/nerves_hub/devices/log_lines.ex b/lib/nerves_hub/devices/log_lines.ex index dbef40cbe..118d35cd9 100644 --- a/lib/nerves_hub/devices/log_lines.ex +++ b/lib/nerves_hub/devices/log_lines.ex @@ -6,6 +6,7 @@ defmodule NervesHub.Devices.LogLines do alias NervesHub.AnalyticsRepo alias NervesHub.Devices.Device alias NervesHub.Devices.LogLine + alias Phoenix.Channel.Server import Ecto.Query @@ -53,13 +54,8 @@ defmodule NervesHub.Devices.LogLines do {:ok, log_line} -> _ = AnalyticsRepo.insert_all(LogLine, [changeset.changes], settings: [async_insert: 1]) - _ = - Phoenix.Channel.Server.broadcast( - NervesHub.PubSub, - "device:#{device.identifier}:internal", - "logs:received", - log_line - ) + topic = "device:#{device.identifier}:internal" + _ = Server.broadcast(NervesHub.PubSub, topic, "logs:received", log_line) {:ok, log_line} diff --git a/lib/nerves_hub/emails/closing_block.ex b/lib/nerves_hub/emails/closing_block.ex index a14538590..16bbf30ab 100644 --- a/lib/nerves_hub/emails/closing_block.ex +++ b/lib/nerves_hub/emails/closing_block.ex @@ -2,15 +2,17 @@ defmodule NervesHub.Emails.ClosingBlock do use MjmlEEx.Component, mode: :runtime use NervesHubWeb, :html + alias Phoenix.HTML + @impl MjmlEEx.Component def render(_assigns) do """ - #{support_section() |> Phoenix.HTML.Safe.to_iodata()} + #{HTML.Safe.to_iodata(support_section())} - #{signoff() |> Phoenix.HTML.Safe.to_iodata()} + #{HTML.Safe.to_iodata(signoff())} """ diff --git a/lib/nerves_hub/extensions.ex b/lib/nerves_hub/extensions.ex index 1cb31cc3c..046dcff49 100644 --- a/lib/nerves_hub/extensions.ex +++ b/lib/nerves_hub/extensions.ex @@ -15,6 +15,8 @@ defmodule NervesHub.Extensions do critical firmware update. """ + alias Phoenix.Channel.Server + @callback handle_in(event :: String.t(), Phoenix.Channel.payload(), Phoenix.Socket.t()) :: {:noreply, Phoenix.Socket.t()} | {:noreply, Phoenix.Socket.t(), timeout() | :hibernate} @@ -77,15 +79,8 @@ defmodule NervesHub.Extensions do end def broadcast_extension_event(target, event, extension) do - Phoenix.Channel.Server.broadcast_from!( - NervesHub.PubSub, - self(), - topic(target), - event, - %{ - "extensions" => [extension] - } - ) + params = %{"extensions" => [extension]} + Server.broadcast_from!(NervesHub.PubSub, self(), topic(target), event, params) end defp topic(%NervesHub.Devices.Device{} = device), do: "device:#{device.id}:extensions" diff --git a/lib/nerves_hub/extensions/geo.ex b/lib/nerves_hub/extensions/geo.ex index 6d485d2b2..0290d4c22 100644 --- a/lib/nerves_hub/extensions/geo.ex +++ b/lib/nerves_hub/extensions/geo.ex @@ -2,6 +2,7 @@ defmodule NervesHub.Extensions.Geo do @behaviour NervesHub.Extensions alias NervesHub.Devices.Connections + alias Phoenix.Channel.Server @impl NervesHub.Extensions def description() do @@ -49,14 +50,9 @@ defmodule NervesHub.Extensions.Geo do @impl NervesHub.Extensions def handle_in("location:update", location, socket) do Connections.merge_update_metadata(socket.assigns.reference_id, %{location: location}) - - _ = - Phoenix.Channel.Server.broadcast( - NervesHub.PubSub, - "device:#{socket.assigns.device.identifier}:internal", - "location:updated", - location - ) + event = "location:updated" + topic = "device:#{socket.assigns.device.identifier}:internal" + _ = Server.broadcast(NervesHub.PubSub, topic, event, location) {:noreply, socket} end diff --git a/lib/nerves_hub/extensions/health.ex b/lib/nerves_hub/extensions/health.ex index 90b285ae8..750095fc4 100644 --- a/lib/nerves_hub/extensions/health.ex +++ b/lib/nerves_hub/extensions/health.ex @@ -5,6 +5,7 @@ defmodule NervesHub.Extensions.Health do alias NervesHub.Devices.HealthStatus alias NervesHub.Devices.Metrics alias NervesHub.Helpers.Logging + alias Phoenix.Channel.Server require Logger @@ -109,7 +110,6 @@ defmodule NervesHub.Extensions.Health do defp device_internal_broadcast!(device, event, payload) do topic = "device:#{device.id}:extensions" - - Phoenix.Channel.Server.broadcast_from!(NervesHub.PubSub, self(), topic, event, payload) + Server.broadcast_from!(NervesHub.PubSub, self(), topic, event, payload) end end diff --git a/lib/nerves_hub/tracker.ex b/lib/nerves_hub/tracker.ex index ecc872ba1..a4fec0763 100644 --- a/lib/nerves_hub/tracker.ex +++ b/lib/nerves_hub/tracker.ex @@ -5,15 +5,11 @@ defmodule NervesHub.Tracker do alias NervesHub.Devices.Device alias NervesHub.Repo + alias Phoenix.Channel.Server, as: ChannelServer def heartbeat(%Device{} = device) do - _ = - Phoenix.Channel.Server.broadcast( - NervesHub.PubSub, - "device:#{device.identifier}:internal", - "connection:heartbeat", - %{} - ) + topic = "device:#{device.identifier}:internal" + _ = ChannelServer.broadcast(NervesHub.PubSub, topic, "connection:heartbeat", %{}) :ok end @@ -31,16 +27,9 @@ defmodule NervesHub.Tracker do end def confirm_online(%Device{identifier: identifier}) do - _ = - Phoenix.Channel.Server.broadcast( - NervesHub.PubSub, - "device:#{identifier}:internal", - "connection:status", - %{ - device_id: identifier, - status: "online" - } - ) + topic = "device:#{identifier}:internal" + params = %{device_id: identifier, status: "online"} + _ = ChannelServer.broadcast(NervesHub.PubSub, topic, "connection:status", params) :ok end @@ -53,16 +42,9 @@ defmodule NervesHub.Tracker do end defp publish(identifier, status) do - _ = - Phoenix.Channel.Server.broadcast( - NervesHub.PubSub, - "device:#{identifier}:internal", - "connection:change", - %{ - device_id: identifier, - status: status - } - ) + topic = "device:#{identifier}:internal" + params = %{device_id: identifier, status: status} + _ = ChannelServer.broadcast(NervesHub.PubSub, topic, "connection:change", params) :ok end @@ -101,12 +83,8 @@ defmodule NervesHub.Tracker do end def console_active?(device_id) do - _ = - Phoenix.PubSub.broadcast( - NervesHub.PubSub, - "device:console:#{device_id}", - {:active?, self()} - ) + topic = "device:console:#{device_id}" + _ = Phoenix.PubSub.broadcast(NervesHub.PubSub, topic, {:active?, self()}) receive do :active -> diff --git a/lib/nerves_hub_web/components/core_components.ex b/lib/nerves_hub_web/components/core_components.ex index 910d9cdb5..84c06805e 100644 --- a/lib/nerves_hub_web/components/core_components.ex +++ b/lib/nerves_hub_web/components/core_components.ex @@ -18,6 +18,8 @@ defmodule NervesHubWeb.CoreComponents do import NervesHubWeb.Components.Icons + alias Phoenix.HTML.Form + alias Phoenix.LiveView.JS use Gettext, backend: NervesHubWeb.Gettext @@ -357,9 +359,7 @@ defmodule NervesHubWeb.CoreComponents do def input(%{type: "checkbox"} = assigns) do assigns = - assign_new(assigns, :checked, fn -> - Phoenix.HTML.Form.normalize_value("checkbox", assigns[:value]) - end) + assign_new(assigns, :checked, fn -> Form.normalize_value("checkbox", assigns[:value]) end) ~H"""
diff --git a/lib/nerves_hub_web/components/device_update_status.ex b/lib/nerves_hub_web/components/device_update_status.ex index 93953cd07..f4ba30221 100644 --- a/lib/nerves_hub_web/components/device_update_status.ex +++ b/lib/nerves_hub_web/components/device_update_status.ex @@ -56,36 +56,24 @@ defmodule NervesHubWeb.Components.DeviceUpdateStatus do end def friendly_blocked_until(blocked_until) do - cond do - DateTime.diff(blocked_until, DateTime.utc_now(), :second) < 60 -> - "for less than a minute" - - DateTime.diff(blocked_until, DateTime.utc_now(), :minute) < 2 -> - "for around a minute" - - DateTime.diff(blocked_until, DateTime.utc_now(), :minute) < 55 -> - "for #{DateTime.diff(blocked_until, DateTime.utc_now(), :minute)} minutes" - - DateTime.diff(blocked_until, DateTime.utc_now(), :minute) < 60 -> - "for less than an hour" - - DateTime.diff(blocked_until, DateTime.utc_now(), :minute) < 63 -> - "for an hour" - - DateTime.diff(blocked_until, DateTime.utc_now(), :minute) < 80 -> - "for just over an hour" + now = DateTime.utc_now() + seconds_diff = DateTime.diff(blocked_until, now, :second) + minutes_diff = DateTime.diff(blocked_until, now, :minute) + hours_diff = DateTime.diff(blocked_until, now, :hour) - DateTime.diff(blocked_until, DateTime.utc_now(), :minute) < 100 -> - "for an hour and a half" - - DateTime.diff(blocked_until, DateTime.utc_now(), :minute) < 110 -> - "for around 2 hours" + format_time_duration(seconds_diff, minutes_diff, hours_diff, blocked_until) + end - DateTime.diff(blocked_until, DateTime.utc_now(), :hour) < 24 -> - "for #{DateTime.diff(blocked_until, DateTime.utc_now(), :hour)} hours" + defp format_time_duration(s, _m, _h, _b_u) when s < 60, do: "for less than a minute" + defp format_time_duration(_s, m, _h, _b_u) when m < 2, do: "for around a minute" + defp format_time_duration(_s, m, _h, _b_u) when m < 55, do: "for #{m} minutes" + defp format_time_duration(_s, m, _h, _b_u) when m < 60, do: "for less than an hour" + defp format_time_duration(_s, m, _h, _b_u) when m < 63, do: "for an hour" + defp format_time_duration(_s, m, _h, _b_u) when m < 80, do: "for just over an hour" + defp format_time_duration(_s, m, _h, _b_u) when m < 100, do: "for an hour and a half" + defp format_time_duration(_s, m, _h, _b_u) when m < 110, do: "for around 2 hours" + defp format_time_duration(_s, _m, h, _b_u) when h < 24, do: "for #{h} hours" - true -> - "until #{Calendar.strftime(blocked_until, "%B %-d, %Y %-I:%M %p %Z")}" - end - end + defp format_time_duration(_s, _m, _h, blocked_until), + do: "until #{Calendar.strftime(blocked_until, "%B %-d, %Y %-I:%M %p %Z")}" end diff --git a/lib/nerves_hub_web/controllers/api/openapi/device_controller_specs.ex b/lib/nerves_hub_web/controllers/api/openapi/device_controller_specs.ex index 65aaa786f..49bcbd649 100644 --- a/lib/nerves_hub_web/controllers/api/openapi/device_controller_specs.ex +++ b/lib/nerves_hub_web/controllers/api/openapi/device_controller_specs.ex @@ -1,8 +1,8 @@ defmodule NervesHubWeb.API.OpenAPI.DeviceControllerSpecs do import OpenApiSpex.Operation, only: [request_body: 4, response: 3] - alias NervesHubWeb.API.Schemas.DeviceSchemas alias NervesHubWeb.API.Schemas.DeviceCertificateSchemas + alias NervesHubWeb.API.Schemas.DeviceSchemas @organization_parameter %OpenApiSpex.Parameter{ name: :org_name, diff --git a/lib/nerves_hub_web/controllers/session_controller.ex b/lib/nerves_hub_web/controllers/session_controller.ex index a5be825a3..74c852a1e 100644 --- a/lib/nerves_hub_web/controllers/session_controller.ex +++ b/lib/nerves_hub_web/controllers/session_controller.ex @@ -3,8 +3,8 @@ defmodule NervesHubWeb.SessionController do alias NervesHub.Accounts alias NervesHub.Accounts.User - alias NervesHub.Accounts.UserToken alias NervesHub.Accounts.UserNotifier + alias NervesHub.Accounts.UserToken alias NervesHubWeb.Auth diff --git a/lib/nerves_hub_web/dynamic_config_multipart.ex b/lib/nerves_hub_web/dynamic_config_multipart.ex index 8ac5263fd..5ae7b479a 100644 --- a/lib/nerves_hub_web/dynamic_config_multipart.ex +++ b/lib/nerves_hub_web/dynamic_config_multipart.ex @@ -12,6 +12,8 @@ defmodule NervesHubWeb.DynamicConfigMultipart do """ @behaviour Plug.Parsers + alias Plug.Parsers.MULTIPART + @impl Plug.Parsers def init(opts) do # This is called at compile time by default so adding options in runtime.exs @@ -27,9 +29,9 @@ defmodule NervesHubWeb.DynamicConfigMultipart do plug_opts = opts |> Keyword.put_new_lazy(:length, fn -> max_file_size(conn) end) - |> Plug.Parsers.MULTIPART.init() + |> MULTIPART.init() - Plug.Parsers.MULTIPART.parse(conn, "multipart", subtype, headers, plug_opts) + MULTIPART.parse(conn, "multipart", subtype, headers, plug_opts) end def parse(conn, _type, _subtype, _headers, _opts) do diff --git a/lib/nerves_hub_web/live/deployment_groups/index.ex b/lib/nerves_hub_web/live/deployment_groups/index.ex index a8102e530..4dad3b9fc 100644 --- a/lib/nerves_hub_web/live/deployment_groups/index.ex +++ b/lib/nerves_hub_web/live/deployment_groups/index.ex @@ -6,9 +6,9 @@ defmodule NervesHubWeb.Live.DeploymentGroups.Index do alias NervesHub.ManagedDeployments alias NervesHub.ManagedDeployments.DeploymentGroup + alias NervesHubWeb.Components.FilterSidebar alias NervesHubWeb.Components.Pager alias NervesHubWeb.Components.Sorting - alias NervesHubWeb.Components.FilterSidebar @default_filters %{ name: "", diff --git a/lib/nerves_hub_web/plugs/configure_uploads.ex b/lib/nerves_hub_web/plugs/configure_uploads.ex index 165f59d09..f28cfa6c4 100644 --- a/lib/nerves_hub_web/plugs/configure_uploads.ex +++ b/lib/nerves_hub_web/plugs/configure_uploads.ex @@ -1,13 +1,15 @@ defmodule NervesHubWeb.Plugs.ConfigureUploads do use NervesHubWeb, :plug + alias NervesHubWeb.Plugs + def init(_opts), do: [] def call(conn, _opts) do if local_uploads?() do conn - |> NervesHubWeb.Plugs.FileUpload.call([]) - |> NervesHubWeb.Plugs.StaticUploads.call([]) + |> Plugs.FileUpload.call([]) + |> Plugs.StaticUploads.call([]) else conn end diff --git a/lib/nerves_hub_web/plugs/im_alive.ex b/lib/nerves_hub_web/plugs/im_alive.ex index 347dbf500..16bf24cd2 100644 --- a/lib/nerves_hub_web/plugs/im_alive.ex +++ b/lib/nerves_hub_web/plugs/im_alive.ex @@ -5,12 +5,13 @@ defmodule NervesHubWeb.Plugs.ImAlive do """ import Plug.Conn + alias Ecto.Adapters.SQL @status_path "/status/alive" def init(config), do: config def call(%{request_path: @status_path} = conn, _) do - case Ecto.Adapters.SQL.query(NervesHub.Repo, "SELECT true", []) do + case SQL.query(NervesHub.Repo, "SELECT true", []) do {:ok, _} -> send_result(conn, 200, "Hello, Friend!") _result -> send_result(conn, 500, "Sorry, Friend :(") end diff --git a/lib/nerves_hub_web/views/layout_view.ex b/lib/nerves_hub_web/views/layout_view.ex index 4ac31ee86..da92d5a76 100644 --- a/lib/nerves_hub_web/views/layout_view.ex +++ b/lib/nerves_hub_web/views/layout_view.ex @@ -6,6 +6,7 @@ defmodule NervesHubWeb.LayoutView do alias NervesHub.Accounts.User alias NervesHub.Devices alias NervesHub.Products.Product + alias Timex.Format.Duration.Formatter, as: TimexFormatter def product(%{assigns: %{product: %Product{} = product}}) do product @@ -48,7 +49,7 @@ defmodule NervesHubWeb.LayoutView do def humanize_seconds(seconds) do seconds |> Timex.Duration.from_seconds() - |> Timex.Format.Duration.Formatter.format(:humanized) + |> TimexFormatter.format(:humanized) end @doc """ diff --git a/test/nerves_hub/devices_test.exs b/test/nerves_hub/devices_test.exs index ee9a222d2..9ce5c4b0c 100644 --- a/test/nerves_hub/devices_test.exs +++ b/test/nerves_hub/devices_test.exs @@ -15,6 +15,7 @@ defmodule NervesHub.DevicesTest do alias NervesHub.Fixtures alias NervesHub.ManagedDeployments alias NervesHub.Products + alias NervesHub.Support.Fwup alias NervesHub.Repo @@ -872,19 +873,14 @@ defmodule NervesHub.DevicesTest do # create some firmware which can be uploaded to each org {:ok, _} = - NervesHub.Support.Fwup.create_firmware(tmp_dir, "old-firmware", %{ + Fwup.create_firmware(tmp_dir, "old-firmware", %{ product: "Same Product Name", fwup_version: "1.13.0" }) # sign and upload for org one {:ok, signed_firmware_one} = - NervesHub.Support.Fwup.sign_firmware( - tmp_dir, - org_key_one.name, - "old-firmware", - "old-firmware-signed-one" - ) + Fwup.sign_firmware(tmp_dir, org_key_one.name, "old-firmware", "old-firmware-signed-one") {:ok, old_firmware_one} = Firmwares.create_firmware(org_one, signed_firmware_one) @@ -894,12 +890,7 @@ defmodule NervesHub.DevicesTest do # sign and upload for org two {:ok, old_signed_firmware_two} = - NervesHub.Support.Fwup.sign_firmware( - tmp_dir, - org_key_two.name, - "old-firmware", - "old-firmware-signed-two" - ) + Fwup.sign_firmware(tmp_dir, org_key_two.name, "old-firmware", "old-firmware-signed-two") {:ok, old_firmware_two} = Firmwares.create_firmware(org_two, old_signed_firmware_two) @@ -909,19 +900,14 @@ defmodule NervesHub.DevicesTest do # and now create some new firmware which can be uploaded to each org {:ok, _} = - NervesHub.Support.Fwup.create_firmware(tmp_dir, "new-firmware", %{ + Fwup.create_firmware(tmp_dir, "new-firmware", %{ product: "Same Product Name", fwup_version: "1.13.0" }) # sign and upload for org one {:ok, new_signed_firmware_one} = - NervesHub.Support.Fwup.sign_firmware( - tmp_dir, - org_key_one.name, - "new-firmware", - "new-firmware-signed-one" - ) + Fwup.sign_firmware(tmp_dir, org_key_one.name, "new-firmware", "new-firmware-signed-one") {:ok, new_firmware_one} = Firmwares.create_firmware(org_one, new_signed_firmware_one) @@ -931,12 +917,7 @@ defmodule NervesHub.DevicesTest do # sign and upload for org two {:ok, new_signed_firmware_two} = - NervesHub.Support.Fwup.sign_firmware( - tmp_dir, - org_key_two.name, - "new-firmware", - "new-firmware-signed-two" - ) + Fwup.sign_firmware(tmp_dir, org_key_two.name, "new-firmware", "new-firmware-signed-two") {:ok, new_firmware_two} = Firmwares.create_firmware(org_two, new_signed_firmware_two) diff --git a/test/nerves_hub/firmwares_test.exs b/test/nerves_hub/firmwares_test.exs index ae45b65e9..8a262609d 100644 --- a/test/nerves_hub/firmwares_test.exs +++ b/test/nerves_hub/firmwares_test.exs @@ -6,9 +6,9 @@ defmodule NervesHub.FirmwaresTest do import Ecto.Query alias NervesHub.Firmwares - alias NervesHub.Firmwares.UpdateTool.Fwup, as: UpdateToolDefault alias NervesHub.Firmwares.Firmware alias NervesHub.Firmwares.FirmwareDelta + alias NervesHub.Firmwares.UpdateTool.Fwup, as: UpdateToolDefault alias NervesHub.Firmwares.Upload.File, as: UploadFile alias NervesHub.Fixtures alias NervesHub.Repo diff --git a/test/nerves_hub/ssl_test.exs b/test/nerves_hub/ssl_test.exs index 97370f49b..44b88bf94 100644 --- a/test/nerves_hub/ssl_test.exs +++ b/test/nerves_hub/ssl_test.exs @@ -4,6 +4,7 @@ defmodule NervesHub.SSLTest do alias NervesHub.Certificate alias NervesHub.Devices alias NervesHub.Fixtures + alias X509.Certificate.Validity require X509.ASN1 @@ -388,7 +389,7 @@ defmodule NervesHub.SSLTest do defp do_corruption(cert, :expired) do {:ok, not_before, 0} = DateTime.from_iso8601("2018-01-01T00:00:00Z") {:ok, not_after, 0} = DateTime.from_iso8601("2018-12-31T23:59:59Z") - new_validity = X509.Certificate.Validity.new(not_before, not_after) + new_validity = Validity.new(not_before, not_after) tbs_cert = X509.ASN1.otp_certificate(cert, :tbsCertificate) new_tbs_cert = X509.ASN1.tbs_certificate(tbs_cert, validity: new_validity) diff --git a/test/nerves_hub_web/channels/device_events_stream_channel_test.exs b/test/nerves_hub_web/channels/device_events_stream_channel_test.exs index 4b8f53588..d8921f3e1 100644 --- a/test/nerves_hub_web/channels/device_events_stream_channel_test.exs +++ b/test/nerves_hub_web/channels/device_events_stream_channel_test.exs @@ -1,10 +1,10 @@ defmodule NervesHubWeb.DeviceEventsStreamChannelTest do use NervesHubWeb.ChannelCase - alias NervesHub.Fixtures alias NervesHub.Accounts - alias NervesHubWeb.EventStreamSocket + alias NervesHub.Fixtures alias NervesHubWeb.DeviceEventsStreamChannel + alias NervesHubWeb.EventStreamSocket describe "handle_info/2" do test "handles fwup_progress messages" do diff --git a/test/nerves_hub_web/channels/websocket_test.exs b/test/nerves_hub_web/channels/websocket_test.exs index ef1dc1eec..713ae3b55 100644 --- a/test/nerves_hub_web/channels/websocket_test.exs +++ b/test/nerves_hub_web/channels/websocket_test.exs @@ -18,6 +18,8 @@ defmodule NervesHubWeb.WebsocketTest do alias NervesHub.Support.Utils alias NervesHubWeb.DeviceEndpoint alias NervesHubWeb.Endpoint + alias X509.Certificate.Template, as: X509Template + alias X509.Certificate.Validity, as: X509Validity import Ecto.Query @@ -184,7 +186,7 @@ defmodule NervesHubWeb.WebsocketTest do key |> X509.PublicKey.derive() |> X509.Certificate.new("CN=#{device.identifier}", ca, ca_key, - validity: X509.Certificate.Validity.new(not_before, not_after) + validity: X509Validity.new(not_before, not_after) ) # Verify our cert is indeed expired @@ -240,15 +242,11 @@ defmodule NervesHubWeb.WebsocketTest do not_before = DateTime.utc_now() |> Timex.shift(days: -3) not_after = DateTime.utc_now() |> Timex.shift(days: -1) - validity = X509.Certificate.Validity.new(not_before, not_after) + validity = X509Validity.new(not_before, not_after) ca_key = X509.PrivateKey.new_ec(:secp256r1) - ca = - X509.Certificate.self_signed(ca_key, "CN=#{org.name}", - template: :root_ca, - validity: validity - ) + ca = X509.Certificate.self_signed(ca_key, "CN=#{org.name}", template: :root_ca, validity: validity) serial = NervesHub.Certificate.get_serial_number(ca) @@ -1005,10 +1003,7 @@ defmodule NervesHubWeb.WebsocketTest do not_before = DateTime.utc_now() |> Timex.shift(days: -1) not_after = DateTime.utc_now() |> Timex.shift(seconds: 1) - template = - X509.Certificate.Template.new(:root_ca, - validity: X509.Certificate.Validity.new(not_before, not_after) - ) + template = X509Template.new(:root_ca, validity: X509.Validity.new(not_before, not_after)) %{cert: ca, key: ca_key} = Fixtures.ca_certificate_fixture(org, template: template) diff --git a/test/nerves_hub_web/live/new_ui/devices/logs_tab_test.exs b/test/nerves_hub_web/live/new_ui/devices/logs_tab_test.exs index 0751caecf..04e4b6e36 100644 --- a/test/nerves_hub_web/live/new_ui/devices/logs_tab_test.exs +++ b/test/nerves_hub_web/live/new_ui/devices/logs_tab_test.exs @@ -1,9 +1,9 @@ defmodule NervesHubWeb.Live.NewUI.Devices.LogsTabTest do use NervesHubWeb.ConnCase.Browser, async: false - alias NervesHub.Products.Product alias NervesHub.Devices.Device alias NervesHub.Devices.LogLines + alias NervesHub.Products.Product alias NervesHub.Repo setup %{conn: conn} do diff --git a/test/nerves_hub_web/live/new_ui/devices/settings_tab_test.exs b/test/nerves_hub_web/live/new_ui/devices/settings_tab_test.exs index c1df0f0da..20d25adab 100644 --- a/test/nerves_hub_web/live/new_ui/devices/settings_tab_test.exs +++ b/test/nerves_hub_web/live/new_ui/devices/settings_tab_test.exs @@ -1,9 +1,9 @@ defmodule NervesHubWeb.NewUi.Devices.SettingsTabTest do use NervesHubWeb.ConnCase.Browser, async: false - alias NervesHubWeb.Components.Utils alias NervesHub.Devices alias NervesHub.Repo + alias NervesHubWeb.Components.Utils setup %{conn: conn} do [conn: init_test_session(conn, %{"new_ui" => true})] diff --git a/test/nerves_hub_web/plugs/org_user_test.exs b/test/nerves_hub_web/plugs/org_user_test.exs index 73e386613..24318b8ab 100644 --- a/test/nerves_hub_web/plugs/org_user_test.exs +++ b/test/nerves_hub_web/plugs/org_user_test.exs @@ -5,6 +5,7 @@ defmodule NervesHubWeb.Plugs.OrgUserTest do alias NervesHub.Accounts alias NervesHub.Fixtures + alias NervesHubWeb.Plugs setup context do {:ok, org_user} = Accounts.get_org_user(context.org, context.user) @@ -16,7 +17,7 @@ defmodule NervesHubWeb.Plugs.OrgUserTest do conn |> Map.put(:assigns, %{org: org}) |> Map.put(:params, %{"user_id" => org_user.user_id}) - |> NervesHubWeb.Plugs.OrgUser.call([]) + |> Plugs.OrgUser.call([]) assert conn.assigns.org_user == org_user end @@ -26,7 +27,7 @@ defmodule NervesHubWeb.Plugs.OrgUserTest do conn |> Map.put(:assigns, %{org: org}) |> Map.put(:params, %{"user_id" => 000}) - |> NervesHubWeb.Plugs.OrgUser.call([]) + |> Plugs.OrgUser.call([]) assert html_response(conn, 404) =~ "Sorry, the page you are looking for does not exist." end @@ -38,7 +39,7 @@ defmodule NervesHubWeb.Plugs.OrgUserTest do conn |> Map.put(:assigns, %{org: org}) |> Map.put(:params, %{"user_id" => user2.id}) - |> NervesHubWeb.Plugs.OrgUser.call([]) + |> Plugs.OrgUser.call([]) assert html_response(conn, 404) =~ "Sorry, the page you are looking for does not exist." end diff --git a/test/nerves_hub_web/views/api/error_view_test.exs b/test/nerves_hub_web/views/api/error_view_test.exs index 4a9be4c93..37c57bb0c 100644 --- a/test/nerves_hub_web/views/api/error_view_test.exs +++ b/test/nerves_hub_web/views/api/error_view_test.exs @@ -1,20 +1,20 @@ defmodule NervesHubWeb.API.ErrorJSONTest do + @moduledoc false use NervesHubWeb.APIConnCase, async: true + alias NervesHubWeb.API.ErrorJSON + + @message "Resource Not Found or Authorization Insufficient" + test "renders 401.json" do - assert NervesHubWeb.API.ErrorJSON.render("401.json", %{}) == %{ - errors: %{detail: "Resource Not Found or Authorization Insufficient"} - } + assert ErrorJSON.render("401.json", %{}) == %{errors: %{detail: @message}} end test "renders 404.json" do - assert NervesHubWeb.API.ErrorJSON.render("404.json", %{}) == %{ - errors: %{detail: "Resource Not Found or Authorization Insufficient"} - } + assert ErrorJSON.render("404.json", %{}) == %{errors: %{detail: @message}} end test "renders 500.json" do - assert NervesHubWeb.API.ErrorJSON.render("500.json", %{}) == - %{errors: %{detail: "Internal Server Error"}} + assert ErrorJSON.render("500.json", %{}) == %{errors: %{detail: "Internal Server Error"}} end end diff --git a/test/support/channel_case.ex b/test/support/channel_case.ex index 101a2d699..97084bea6 100644 --- a/test/support/channel_case.ex +++ b/test/support/channel_case.ex @@ -15,6 +15,8 @@ defmodule NervesHubWeb.ChannelCase do use ExUnit.CaseTemplate + alias Ecto.Adapters.SQL.Sandbox + using do quote do # Import conveniences for testing with channels @@ -54,17 +56,17 @@ defmodule NervesHubWeb.ChannelCase do setup do # Explicitly get a connection before each test - :ok = Ecto.Adapters.SQL.Sandbox.checkout(NervesHub.Repo) - :ok = Ecto.Adapters.SQL.Sandbox.checkout(NervesHub.ObanRepo) + :ok = Sandbox.checkout(NervesHub.Repo) + :ok = Sandbox.checkout(NervesHub.ObanRepo) end setup tags do - pid = Ecto.Adapters.SQL.Sandbox.start_owner!(NervesHub.Repo, shared: not tags[:async]) - pid2 = Ecto.Adapters.SQL.Sandbox.start_owner!(NervesHub.ObanRepo, shared: not tags[:async]) + pid = Sandbox.start_owner!(NervesHub.Repo, shared: not tags[:async]) + pid2 = Sandbox.start_owner!(NervesHub.ObanRepo, shared: not tags[:async]) on_exit(fn -> - Ecto.Adapters.SQL.Sandbox.stop_owner(pid) - Ecto.Adapters.SQL.Sandbox.stop_owner(pid2) + Sandbox.stop_owner(pid) + Sandbox.stop_owner(pid2) end) :ok diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex index 8cce8329e..e5483270f 100644 --- a/test/support/conn_case.ex +++ b/test/support/conn_case.ex @@ -15,6 +15,9 @@ defmodule NervesHubWeb.ConnCase do use ExUnit.CaseTemplate + alias Ecto.Adapters.SQL.Sandbox + alias Phoenix.ConnTest + using do quote do use NervesHubWeb, :verified_routes @@ -31,13 +34,13 @@ defmodule NervesHubWeb.ConnCase do end setup tags do - :ok = Ecto.Adapters.SQL.Sandbox.checkout(NervesHub.Repo) + :ok = Sandbox.checkout(NervesHub.Repo) if !tags[:async] do - Ecto.Adapters.SQL.Sandbox.mode(NervesHub.Repo, {:shared, self()}) + Sandbox.mode(NervesHub.Repo, {:shared, self()}) end - {:ok, conn: Phoenix.ConnTest.build_conn()} + {:ok, conn: ConnTest.build_conn()} end end @@ -57,6 +60,8 @@ defmodule NervesHubWeb.APIConnCase do """ use ExUnit.CaseTemplate + + alias Ecto.Adapters.SQL.Sandbox alias NervesHub.Fixtures using do @@ -85,10 +90,10 @@ defmodule NervesHubWeb.APIConnCase do end setup tags do - :ok = Ecto.Adapters.SQL.Sandbox.checkout(NervesHub.Repo) + :ok = Sandbox.checkout(NervesHub.Repo) if !tags[:async] do - Ecto.Adapters.SQL.Sandbox.mode(NervesHub.Repo, {:shared, self()}) + Sandbox.mode(NervesHub.Repo, {:shared, self()}) end user = Fixtures.user_fixture() diff --git a/test/support/data_case.ex b/test/support/data_case.ex index 85e5dd1fa..997fc0149 100644 --- a/test/support/data_case.ex +++ b/test/support/data_case.ex @@ -14,6 +14,8 @@ defmodule NervesHub.DataCase do use ExUnit.CaseTemplate + alias Ecto.Adapters.SQL.Sandbox + using do quote do use DefaultMocks @@ -31,12 +33,12 @@ defmodule NervesHub.DataCase do end setup tags do - :ok = Ecto.Adapters.SQL.Sandbox.checkout(NervesHub.Repo) - :ok = Ecto.Adapters.SQL.Sandbox.checkout(NervesHub.ObanRepo) + :ok = Sandbox.checkout(NervesHub.Repo) + :ok = Sandbox.checkout(NervesHub.ObanRepo) if !tags[:async] do - Ecto.Adapters.SQL.Sandbox.mode(NervesHub.Repo, {:shared, self()}) - Ecto.Adapters.SQL.Sandbox.mode(NervesHub.ObanRepo, {:shared, self()}) + Sandbox.mode(NervesHub.Repo, {:shared, self()}) + Sandbox.mode(NervesHub.ObanRepo, {:shared, self()}) end :ok diff --git a/test/support/fixtures.ex b/test/support/fixtures.ex index 9b5b85f53..6848f518f 100644 --- a/test/support/fixtures.ex +++ b/test/support/fixtures.ex @@ -17,7 +17,10 @@ defmodule NervesHub.Fixtures do alias NervesHub.Repo alias NervesHub.Scripts alias NervesHub.Support - alias NervesHub.Support.Fwup + alias NervesHub.Support.Fwup, as: SupportFwup + alias X509.Certificate.Extension, as: X509Extension + alias X509.Certificate.Template, as: X509Template + alias X509.Certificate.Validity, as: X509Validity @uploader Application.compile_env(:nerves_hub, :firmware_upload) @@ -25,10 +28,7 @@ defmodule NervesHub.Fixtures do @deployment_group_params %{ name: "Test Deployment", - conditions: %{ - "version" => "<= 1.0.0", - "tags" => ["beta", "beta-edge"] - }, + conditions: %{"version" => "<= 1.0.0", "tags" => ["beta", "beta-edge"]}, is_active: false, delta_updatable: false } @@ -85,15 +85,9 @@ defmodule NervesHub.Fixtures do def org_key_fixture(%Accounts.Org{} = org, %Accounts.User{} = user, dir \\ System.tmp_dir()) do fwup_key_name = "org_key-#{counter()}" - Fwup.gen_key_pair(fwup_key_name, dir) - key = Fwup.get_public_key(fwup_key_name, dir) - - params = %{ - org_id: org.id, - key: key, - name: fwup_key_name, - created_by_id: user.id - } + SupportFwup.gen_key_pair(fwup_key_name, dir) + key = SupportFwup.get_public_key(fwup_key_name, dir) + params = %{org_id: org.id, key: key, name: fwup_key_name, created_by_id: user.id} {:ok, org_key} = Accounts.create_org_key(params) @@ -149,11 +143,11 @@ defmodule NervesHub.Fixtures do @spec firmware_file_fixture(OrgKey.t(), Product.t()) :: String.t() def firmware_file_fixture(%Accounts.OrgKey{} = org_key, %Products.Product{} = product, params \\ %{}) do {:ok, filepath} = - Fwup.create_signed_firmware( + SupportFwup.create_signed_firmware( org_key.name, "unsigned-#{counter()}", "signed-#{counter()}", - %{product: product.name} |> Enum.into(params) + Enum.into(%{product: product.name}, params) ) filepath @@ -334,14 +328,14 @@ defmodule NervesHub.Fixtures do cert = X509.Certificate.new(public_key, subject_rdn, signer_cert, signer_key, template: - X509.Certificate.Template.new(%X509.Certificate.Template{ + X509Template.new(%X509Template{ serial: {:random, 20}, - validity: X509.Certificate.Validity.new(not_before, not_after), + validity: X509Validity.new(not_before, not_after), hash: :sha256, extensions: [ - basic_constraints: X509.Certificate.Extension.basic_constraints(false), - key_usage: X509.Certificate.Extension.key_usage([:digitalSignature, :keyEncipherment]), - ext_key_usage: X509.Certificate.Extension.ext_key_usage([:clientAuth]), + basic_constraints: X509Extension.basic_constraints(false), + key_usage: X509Extension.key_usage([:digitalSignature, :keyEncipherment]), + ext_key_usage: X509Extension.ext_key_usage([:clientAuth]), subject_key_identifier: true, authority_key_identifier: true ] diff --git a/test/support/utils.ex b/test/support/utils.ex index 8c4869e20..33a8e9e9b 100644 --- a/test/support/utils.ex +++ b/test/support/utils.ex @@ -4,12 +4,13 @@ defmodule NervesHub.Support.Utils do alias NervesHub.Accounts.UserToken alias NervesHub.Repo alias NervesHub.Utils.Base62 + alias Plug.Crypto.KeyGenerator def create_v1_user_token!(user) do secret = <> - <> = Plug.Crypto.KeyGenerator.generate(secret, "user-#{user.id}", length: 20) + <> = KeyGenerator.generate(secret, "user-#{user.id}", length: 20) <> = Base62.encode(initial) |> String.pad_leading(30, "0") crc = :erlang.crc32(rand) |> Base62.encode() |> String.pad_leading(6, "0") token = "nhu_#{rand}#{crc}" From 8f23643ed24e5a3f2f7244da4ffeb65bed1f5037 Mon Sep 17 00:00:00 2001 From: Taras Tyshko Date: Fri, 8 Aug 2025 14:04:15 +0300 Subject: [PATCH 05/13] ignore low priority credo checks (TODO, @moduledoc, line length) --- .credo.exs | 12 ++++-------- .github/workflows/ci.yml | 2 +- lib/nerves_hub/accounts.ex | 1 + lib/nerves_hub/accounts/user_notifier.ex | 4 ++-- lib/nerves_hub/application.ex | 6 ++++-- .../live/new_ui/devices/show_test.exs | 8 +++----- test/support/channel_case.ex | 14 +++++++------- 7 files changed, 22 insertions(+), 25 deletions(-) diff --git a/.credo.exs b/.credo.exs index 02f69088f..b8ec2762b 100644 --- a/.credo.exs +++ b/.credo.exs @@ -83,6 +83,8 @@ # {Credo.Check.Design.AliasUsage, [priority: :low, if_nested_deeper_than: 2, if_called_more_often_than: 0]}, + # TODO comments are acceptable in our codebase, but we want to see them + {Credo.Check.Design.TagTODO, [priority: :low]}, {Credo.Check.Design.TagFIXME, []}, # ## Readability Checks @@ -94,6 +96,8 @@ {Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 120]}, {Credo.Check.Readability.ModuleAttributeNames, []}, {Credo.Check.Readability.ModuleNames, []}, + # ModuleDoc is not required in our codebase, but we want to see them + {Credo.Check.Readability.ModuleDoc, [priority: :low]}, {Credo.Check.Readability.MultiAlias, []}, {Credo.Check.Readability.ParenthesesInCondition, []}, {Credo.Check.Readability.ParenthesesOnZeroArityDefs, [parens: true]}, @@ -163,14 +167,6 @@ {Credo.Check.Warning.WrongTestFileExtension, []} ], disabled: [ - # - # TODO comments are acceptable in our codebase - {Credo.Check.Design.TagTODO, []}, - - # - # ModuleDoc is not required in our codebase - {Credo.Check.Readability.ModuleDoc, []}, - # # Checks scheduled for next check update (opt-in for now) {Credo.Check.Refactor.UtcNowTruncate, []}, diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 172d36918..bc07dfe3c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,7 +113,7 @@ jobs: run: mix spellweaver.check - name: Run Credo - run: mix credo + run: mix credo --min-priority normal - name: DB Setup run: mix ecto.migrate.reset diff --git a/lib/nerves_hub/accounts.ex b/lib/nerves_hub/accounts.ex index a67594368..84e678962 100644 --- a/lib/nerves_hub/accounts.ex +++ b/lib/nerves_hub/accounts.ex @@ -3,6 +3,7 @@ defmodule NervesHub.Accounts do alias Ecto.Changeset alias Ecto.Multi + alias NervesHub.Accounts.Invite alias NervesHub.Accounts.Org alias NervesHub.Accounts.OrgKey diff --git a/lib/nerves_hub/accounts/user_notifier.ex b/lib/nerves_hub/accounts/user_notifier.ex index e1103aa1b..2c38ebbf0 100644 --- a/lib/nerves_hub/accounts/user_notifier.ex +++ b/lib/nerves_hub/accounts/user_notifier.ex @@ -17,7 +17,7 @@ defmodule NervesHub.Accounts.UserNotifier do alias NervesHub.Emails.WelcomeTemplate alias NervesHub.SwooshMailer, as: Mailer - alias Phoenix.HTML + alias Phoenix.HTML.Safe, as: HTMLSafe def deliver_confirmation_instructions(user, confirmation_url) do assigns = %{ @@ -208,7 +208,7 @@ defmodule NervesHub.Accounts.UserNotifier do text = module.text_render(assigns) - |> HTML.Safe.to_iodata() + |> HTMLSafe.to_iodata() |> IO.iodata_to_binary() {html, text} diff --git a/lib/nerves_hub/application.ex b/lib/nerves_hub/application.ex index fead89d44..1a0c45894 100644 --- a/lib/nerves_hub/application.ex +++ b/lib/nerves_hub/application.ex @@ -1,7 +1,9 @@ defmodule NervesHub.Application do use Application + require Logger - alias NervesHub.Telemetry.Customizations + + alias NervesHub.Telemetry.Customizations, as: TelemetryCustomizations def start(_type, _args) do case System.cmd("fwup", ["--version"], env: []) do @@ -57,7 +59,7 @@ defmodule NervesHub.Application do :ok = :httpc.set_option(:ipfamily, :inet6fb4) end - :ok = Customizations.setup() + :ok = TelemetryCustomizations.setup() :ok = OpentelemetryBandit.setup() :ok = OpentelemetryPhoenix.setup(adapter: :bandit) :ok = OpentelemetryOban.setup(trace: [:jobs]) diff --git a/test/nerves_hub_web/live/new_ui/devices/show_test.exs b/test/nerves_hub_web/live/new_ui/devices/show_test.exs index afeabf6ef..09c8b7f19 100644 --- a/test/nerves_hub_web/live/new_ui/devices/show_test.exs +++ b/test/nerves_hub_web/live/new_ui/devices/show_test.exs @@ -112,11 +112,9 @@ defmodule NervesHubWeb.Live.NewUI.Devices.ShowTest do end defp user_initials(user) do - String.split(user.name) - |> Enum.map_join("", fn w -> - String.at(w, 0) - |> String.upcase() - end) + user.name + |> String.split() + |> Enum.map_join("", fn w -> String.at(w, 0) |> String.upcase() end) end end diff --git a/test/support/channel_case.ex b/test/support/channel_case.ex index 97084bea6..6d04dc81f 100644 --- a/test/support/channel_case.ex +++ b/test/support/channel_case.ex @@ -15,7 +15,7 @@ defmodule NervesHubWeb.ChannelCase do use ExUnit.CaseTemplate - alias Ecto.Adapters.SQL.Sandbox + alias Ecto.Adapters.SQL.Sandbox, as: SQLSandbox using do quote do @@ -56,17 +56,17 @@ defmodule NervesHubWeb.ChannelCase do setup do # Explicitly get a connection before each test - :ok = Sandbox.checkout(NervesHub.Repo) - :ok = Sandbox.checkout(NervesHub.ObanRepo) + :ok = SQLSandbox.checkout(NervesHub.Repo) + :ok = SQLSandbox.checkout(NervesHub.ObanRepo) end setup tags do - pid = Sandbox.start_owner!(NervesHub.Repo, shared: not tags[:async]) - pid2 = Sandbox.start_owner!(NervesHub.ObanRepo, shared: not tags[:async]) + pid = SQLSandbox.start_owner!(NervesHub.Repo, shared: not tags[:async]) + pid2 = SQLSandbox.start_owner!(NervesHub.ObanRepo, shared: not tags[:async]) on_exit(fn -> - Sandbox.stop_owner(pid) - Sandbox.stop_owner(pid2) + SQLSandbox.stop_owner(pid) + SQLSandbox.stop_owner(pid2) end) :ok From 6d3f18489f0e6e5127efb1fc10986e89a2860e76 Mon Sep 17 00:00:00 2001 From: Taras Tyshko Date: Fri, 8 Aug 2025 16:00:47 +0300 Subject: [PATCH 06/13] set TODO and @moduledoc checks to ignore priority --- .credo.exs | 8 ++-- .github/workflows/ci.yml | 2 +- lib/nerves_hub/certificate.ex | 6 +-- lib/nerves_hub/device_ssl_transport.ex | 40 +++++++++---------- .../components/core_components.ex | 14 ++++--- lib/nerves_hub_web/plugs/configure_uploads.ex | 7 ++-- test/nerves_hub/ssl_test.exs | 4 +- 7 files changed, 42 insertions(+), 39 deletions(-) diff --git a/.credo.exs b/.credo.exs index b8ec2762b..337a6cc18 100644 --- a/.credo.exs +++ b/.credo.exs @@ -83,8 +83,8 @@ # {Credo.Check.Design.AliasUsage, [priority: :low, if_nested_deeper_than: 2, if_called_more_often_than: 0]}, - # TODO comments are acceptable in our codebase, but we want to see them - {Credo.Check.Design.TagTODO, [priority: :low]}, + # TODO comments are acceptable in our codebase, but we want to see them locally + {Credo.Check.Design.TagTODO, [priority: :ignore]}, {Credo.Check.Design.TagFIXME, []}, # ## Readability Checks @@ -96,8 +96,8 @@ {Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 120]}, {Credo.Check.Readability.ModuleAttributeNames, []}, {Credo.Check.Readability.ModuleNames, []}, - # ModuleDoc is not required in our codebase, but we want to see them - {Credo.Check.Readability.ModuleDoc, [priority: :low]}, + # ModuleDoc is not required in our codebase, but we want to see them locally + {Credo.Check.Readability.ModuleDoc, [priority: :ignore]}, {Credo.Check.Readability.MultiAlias, []}, {Credo.Check.Readability.ParenthesesInCondition, []}, {Credo.Check.Readability.ParenthesesOnZeroArityDefs, [parens: true]}, diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc07dfe3c..98cb75586 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,7 +113,7 @@ jobs: run: mix spellweaver.check - name: Run Credo - run: mix credo --min-priority normal + run: mix credo --min-priority low - name: DB Setup run: mix ecto.migrate.reset diff --git a/lib/nerves_hub/certificate.ex b/lib/nerves_hub/certificate.ex index 85761bc4c..0d6982bb7 100644 --- a/lib/nerves_hub/certificate.ex +++ b/lib/nerves_hub/certificate.ex @@ -1,5 +1,5 @@ defmodule NervesHub.Certificate do - alias X509.Certificate.Extension + alias X509.Certificate.Extension, as: X509Extension import X509.ASN1, only: [ @@ -19,7 +19,7 @@ defmodule NervesHub.Certificate do def get_aki(otp_certificate) do otp_certificate |> X509.Certificate.extensions() - |> Extension.find(:authority_key_identifier) + |> X509Extension.find(:authority_key_identifier) |> extension() |> Keyword.get(:extnValue) |> authority_key_identifier() @@ -29,7 +29,7 @@ defmodule NervesHub.Certificate do def get_ski(otp_certificate) do otp_certificate |> X509.Certificate.extensions() - |> Extension.find(:subject_key_identifier) + |> X509Extension.find(:subject_key_identifier) |> case do nil -> nil diff --git a/lib/nerves_hub/device_ssl_transport.ex b/lib/nerves_hub/device_ssl_transport.ex index 9aeadea1f..91dd1cacc 100644 --- a/lib/nerves_hub/device_ssl_transport.ex +++ b/lib/nerves_hub/device_ssl_transport.ex @@ -13,20 +13,20 @@ defmodule NervesHub.DeviceSSLTransport do @behaviour ThousandIsland.Transport - alias ThousandIsland.Transports.SSL + alias ThousandIsland.Transports.SSL, as: SSLTransport @impl ThousandIsland.Transport - defdelegate listen(port, user_options), to: SSL + defdelegate listen(port, user_options), to: SSLTransport @impl ThousandIsland.Transport - defdelegate accept(listener_socket), to: SSL + defdelegate accept(listener_socket), to: SSLTransport @impl ThousandIsland.Transport def handshake(socket) do if NervesHub.RateLimit.increment() do :telemetry.execute([:nerves_hub, :rate_limit, :accepted], %{count: 1}) - SSL.handshake(socket) + SSLTransport.handshake(socket) else :telemetry.execute([:nerves_hub, :rate_limit, :rejected], %{count: 1}) @@ -35,50 +35,50 @@ defmodule NervesHub.DeviceSSLTransport do end @impl ThousandIsland.Transport - defdelegate upgrade(socket, opts), to: SSL + defdelegate upgrade(socket, opts), to: SSLTransport @impl ThousandIsland.Transport - defdelegate controlling_process(socket, pid), to: SSL + defdelegate controlling_process(socket, pid), to: SSLTransport @impl ThousandIsland.Transport - defdelegate recv(socket, length, timeout), to: SSL + defdelegate recv(socket, length, timeout), to: SSLTransport @impl ThousandIsland.Transport - defdelegate send(socket, data), to: SSL + defdelegate send(socket, data), to: SSLTransport @impl ThousandIsland.Transport - defdelegate sendfile(socket, filename, offset, length), to: SSL + defdelegate sendfile(socket, filename, offset, length), to: SSLTransport @impl ThousandIsland.Transport - defdelegate getopts(socket, options), to: SSL + defdelegate getopts(socket, options), to: SSLTransport @impl ThousandIsland.Transport - defdelegate setopts(socket, options), to: SSL + defdelegate setopts(socket, options), to: SSLTransport @impl ThousandIsland.Transport - defdelegate shutdown(socket, way), to: SSL + defdelegate shutdown(socket, way), to: SSLTransport @impl ThousandIsland.Transport - defdelegate close(socket), to: SSL + defdelegate close(socket), to: SSLTransport @impl ThousandIsland.Transport - defdelegate sockname(socket), to: SSL + defdelegate sockname(socket), to: SSLTransport @impl ThousandIsland.Transport - defdelegate peername(socket), to: SSL + defdelegate peername(socket), to: SSLTransport @impl ThousandIsland.Transport - defdelegate peercert(socket), to: SSL + defdelegate peercert(socket), to: SSLTransport @impl ThousandIsland.Transport - defdelegate secure?(), to: SSL + defdelegate secure?(), to: SSLTransport @impl ThousandIsland.Transport - defdelegate getstat(socket), to: SSL + defdelegate getstat(socket), to: SSLTransport @impl ThousandIsland.Transport - defdelegate negotiated_protocol(socket), to: SSL + defdelegate negotiated_protocol(socket), to: SSLTransport @impl ThousandIsland.Transport - defdelegate connection_information(socket), to: SSL + defdelegate connection_information(socket), to: SSLTransport end diff --git a/lib/nerves_hub_web/components/core_components.ex b/lib/nerves_hub_web/components/core_components.ex index 84c06805e..4061775d2 100644 --- a/lib/nerves_hub_web/components/core_components.ex +++ b/lib/nerves_hub_web/components/core_components.ex @@ -18,7 +18,7 @@ defmodule NervesHubWeb.CoreComponents do import NervesHubWeb.Components.Icons - alias Phoenix.HTML.Form + alias Phoenix.HTML.Form, as: HTMLForm alias Phoenix.LiveView.JS @@ -359,7 +359,9 @@ defmodule NervesHubWeb.CoreComponents do def input(%{type: "checkbox"} = assigns) do assigns = - assign_new(assigns, :checked, fn -> Form.normalize_value("checkbox", assigns[:value]) end) + assign_new(assigns, :checked, fn -> + HTMLForm.normalize_value("checkbox", assigns[:value]) + end) ~H"""
@@ -388,7 +390,7 @@ defmodule NervesHubWeb.CoreComponents do {@rest} > - {Phoenix.HTML.Form.options_for_select(@options, @value)} + {HTMLForm.options_for_select(@options, @value)}
{assigns[:hint] || render_slot(assigns[:rich_hint])} @@ -412,7 +414,7 @@ defmodule NervesHubWeb.CoreComponents do @errors != [] && "border-red-500 focus:border-red-500" ]} {@rest} - ><%= Phoenix.HTML.Form.normalize_value("textarea", @value) %> + ><%= HTMLForm.normalize_value("textarea", @value) %>
{assigns[:hint] || render_slot(assigns[:rich_hint])}
@@ -431,7 +433,7 @@ defmodule NervesHubWeb.CoreComponents do type={@type} name={@name} id={@id} - value={Phoenix.HTML.Form.normalize_value(@type, @value)} + value={HTMLForm.normalize_value(@type, @value)} class={[ "mt-2 py-1.5 px-2 block w-full rounded text-zinc-400 bg-zinc-900 focus:ring-0 sm:text-sm", "phx-no-feedback:border-zinc-600 phx-no-feedback:focus:border-zinc-700", @@ -460,7 +462,7 @@ defmodule NervesHubWeb.CoreComponents do type={@type} name={@name} id={@id} - value={Phoenix.HTML.Form.normalize_value(@type, @value)} + value={HTMLForm.normalize_value(@type, @value)} class={[ "mt-2 py-1.5 px-2 block w-full rounded text-zinc-400 bg-zinc-900 focus:ring-0 sm:text-sm", "phx-no-feedback:border-zinc-600 phx-no-feedback:focus:border-zinc-700", diff --git a/lib/nerves_hub_web/plugs/configure_uploads.ex b/lib/nerves_hub_web/plugs/configure_uploads.ex index f28cfa6c4..880874207 100644 --- a/lib/nerves_hub_web/plugs/configure_uploads.ex +++ b/lib/nerves_hub_web/plugs/configure_uploads.ex @@ -1,15 +1,16 @@ defmodule NervesHubWeb.Plugs.ConfigureUploads do use NervesHubWeb, :plug - alias NervesHubWeb.Plugs + alias NervesHubWeb.Plugs.FileUpload + alias NervesHubWeb.Plugs.StaticUploads def init(_opts), do: [] def call(conn, _opts) do if local_uploads?() do conn - |> Plugs.FileUpload.call([]) - |> Plugs.StaticUploads.call([]) + |> FileUpload.call([]) + |> StaticUploads.call([]) else conn end diff --git a/test/nerves_hub/ssl_test.exs b/test/nerves_hub/ssl_test.exs index 44b88bf94..f62d65404 100644 --- a/test/nerves_hub/ssl_test.exs +++ b/test/nerves_hub/ssl_test.exs @@ -4,7 +4,7 @@ defmodule NervesHub.SSLTest do alias NervesHub.Certificate alias NervesHub.Devices alias NervesHub.Fixtures - alias X509.Certificate.Validity + alias X509.Certificate.Validity, as: X509Validity require X509.ASN1 @@ -389,7 +389,7 @@ defmodule NervesHub.SSLTest do defp do_corruption(cert, :expired) do {:ok, not_before, 0} = DateTime.from_iso8601("2018-01-01T00:00:00Z") {:ok, not_after, 0} = DateTime.from_iso8601("2018-12-31T23:59:59Z") - new_validity = Validity.new(not_before, not_after) + new_validity = X509Validity.new(not_before, not_after) tbs_cert = X509.ASN1.otp_certificate(cert, :tbsCertificate) new_tbs_cert = X509.ASN1.tbs_certificate(tbs_cert, validity: new_validity) From 99747f8068fd1a4318cd9d60e9d9c6732d54a6b1 Mon Sep 17 00:00:00 2001 From: Taras Tyshko Date: Fri, 8 Aug 2025 16:06:10 +0300 Subject: [PATCH 07/13] alias Plug.Crypto.KeyGenerator for clarity --- test/support/utils.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/support/utils.ex b/test/support/utils.ex index 33a8e9e9b..b84886470 100644 --- a/test/support/utils.ex +++ b/test/support/utils.ex @@ -4,13 +4,13 @@ defmodule NervesHub.Support.Utils do alias NervesHub.Accounts.UserToken alias NervesHub.Repo alias NervesHub.Utils.Base62 - alias Plug.Crypto.KeyGenerator + alias Plug.Crypto.KeyGenerator, as: CryptoKeyGenerator def create_v1_user_token!(user) do secret = <> - <> = KeyGenerator.generate(secret, "user-#{user.id}", length: 20) + <> = CryptoKeyGenerator.generate(secret, "user-#{user.id}", length: 20) <> = Base62.encode(initial) |> String.pad_leading(30, "0") crc = :erlang.crc32(rand) |> Base62.encode() |> String.pad_leading(6, "0") token = "nhu_#{rand}#{crc}" From b00c95951d7f2508f0d986f02ba31ac79f8a0e9b Mon Sep 17 00:00:00 2001 From: Taras Tyshko Date: Mon, 11 Aug 2025 13:40:39 +0300 Subject: [PATCH 08/13] Extend mix check with credo --min-priority low --- mix.exs | 1 + 1 file changed, 1 insertion(+) diff --git a/mix.exs b/mix.exs index 96dd84182..8706cf0e9 100644 --- a/mix.exs +++ b/mix.exs @@ -180,6 +180,7 @@ defmodule NervesHub.MixProject do "format --check-formatted", "deps.unlock --check-unused", "dialyzer --format github --format dialyxir", + "credo --min-priority low", "spellweaver.check" ] ] From eacb89a6fd97392b7d87840b05c8b2ab0b8d7f73 Mon Sep 17 00:00:00 2001 From: Taras Tyshko Date: Wed, 20 Aug 2025 14:14:18 +0300 Subject: [PATCH 09/13] resolve PR comments round 2 --- lib/nerves_hub/accounts/user_notifier.ex | 4 +-- lib/nerves_hub/devices/log_lines.ex | 4 +-- lib/nerves_hub/extensions.ex | 4 +-- lib/nerves_hub/extensions/geo.ex | 4 +-- lib/nerves_hub/extensions/health.ex | 4 +-- test/nerves_hub/devices_test.exs | 35 ++++++++++++++++++------ test/support/conn_case.ex | 12 ++++---- test/support/data_case.ex | 10 +++---- 8 files changed, 48 insertions(+), 29 deletions(-) diff --git a/lib/nerves_hub/accounts/user_notifier.ex b/lib/nerves_hub/accounts/user_notifier.ex index 2c38ebbf0..e1103aa1b 100644 --- a/lib/nerves_hub/accounts/user_notifier.ex +++ b/lib/nerves_hub/accounts/user_notifier.ex @@ -17,7 +17,7 @@ defmodule NervesHub.Accounts.UserNotifier do alias NervesHub.Emails.WelcomeTemplate alias NervesHub.SwooshMailer, as: Mailer - alias Phoenix.HTML.Safe, as: HTMLSafe + alias Phoenix.HTML def deliver_confirmation_instructions(user, confirmation_url) do assigns = %{ @@ -208,7 +208,7 @@ defmodule NervesHub.Accounts.UserNotifier do text = module.text_render(assigns) - |> HTMLSafe.to_iodata() + |> HTML.Safe.to_iodata() |> IO.iodata_to_binary() {html, text} diff --git a/lib/nerves_hub/devices/log_lines.ex b/lib/nerves_hub/devices/log_lines.ex index 118d35cd9..256cdc3ae 100644 --- a/lib/nerves_hub/devices/log_lines.ex +++ b/lib/nerves_hub/devices/log_lines.ex @@ -6,7 +6,7 @@ defmodule NervesHub.Devices.LogLines do alias NervesHub.AnalyticsRepo alias NervesHub.Devices.Device alias NervesHub.Devices.LogLine - alias Phoenix.Channel.Server + alias Phoenix.Channel.Server, as: ChannelServer import Ecto.Query @@ -55,7 +55,7 @@ defmodule NervesHub.Devices.LogLines do _ = AnalyticsRepo.insert_all(LogLine, [changeset.changes], settings: [async_insert: 1]) topic = "device:#{device.identifier}:internal" - _ = Server.broadcast(NervesHub.PubSub, topic, "logs:received", log_line) + _ = ChannelServer.broadcast(NervesHub.PubSub, topic, "logs:received", log_line) {:ok, log_line} diff --git a/lib/nerves_hub/extensions.ex b/lib/nerves_hub/extensions.ex index 046dcff49..9d5375004 100644 --- a/lib/nerves_hub/extensions.ex +++ b/lib/nerves_hub/extensions.ex @@ -15,7 +15,7 @@ defmodule NervesHub.Extensions do critical firmware update. """ - alias Phoenix.Channel.Server + alias Phoenix.Channel.Server, as: ChannelServer @callback handle_in(event :: String.t(), Phoenix.Channel.payload(), Phoenix.Socket.t()) :: {:noreply, Phoenix.Socket.t()} @@ -80,7 +80,7 @@ defmodule NervesHub.Extensions do def broadcast_extension_event(target, event, extension) do params = %{"extensions" => [extension]} - Server.broadcast_from!(NervesHub.PubSub, self(), topic(target), event, params) + ChannelServer.broadcast_from!(NervesHub.PubSub, self(), topic(target), event, params) end defp topic(%NervesHub.Devices.Device{} = device), do: "device:#{device.id}:extensions" diff --git a/lib/nerves_hub/extensions/geo.ex b/lib/nerves_hub/extensions/geo.ex index 0290d4c22..24220f1b9 100644 --- a/lib/nerves_hub/extensions/geo.ex +++ b/lib/nerves_hub/extensions/geo.ex @@ -2,7 +2,7 @@ defmodule NervesHub.Extensions.Geo do @behaviour NervesHub.Extensions alias NervesHub.Devices.Connections - alias Phoenix.Channel.Server + alias Phoenix.Channel.Server, as: ChannelServer @impl NervesHub.Extensions def description() do @@ -52,7 +52,7 @@ defmodule NervesHub.Extensions.Geo do Connections.merge_update_metadata(socket.assigns.reference_id, %{location: location}) event = "location:updated" topic = "device:#{socket.assigns.device.identifier}:internal" - _ = Server.broadcast(NervesHub.PubSub, topic, event, location) + _ = ChannelServer.broadcast(NervesHub.PubSub, topic, event, location) {:noreply, socket} end diff --git a/lib/nerves_hub/extensions/health.ex b/lib/nerves_hub/extensions/health.ex index 750095fc4..93a6a031c 100644 --- a/lib/nerves_hub/extensions/health.ex +++ b/lib/nerves_hub/extensions/health.ex @@ -5,7 +5,7 @@ defmodule NervesHub.Extensions.Health do alias NervesHub.Devices.HealthStatus alias NervesHub.Devices.Metrics alias NervesHub.Helpers.Logging - alias Phoenix.Channel.Server + alias Phoenix.Channel.Server, as: ChannelServer require Logger @@ -110,6 +110,6 @@ defmodule NervesHub.Extensions.Health do defp device_internal_broadcast!(device, event, payload) do topic = "device:#{device.id}:extensions" - Server.broadcast_from!(NervesHub.PubSub, self(), topic, event, payload) + ChannelServer.broadcast_from!(NervesHub.PubSub, self(), topic, event, payload) end end diff --git a/test/nerves_hub/devices_test.exs b/test/nerves_hub/devices_test.exs index 9ce5c4b0c..9cf6502ab 100644 --- a/test/nerves_hub/devices_test.exs +++ b/test/nerves_hub/devices_test.exs @@ -15,9 +15,8 @@ defmodule NervesHub.DevicesTest do alias NervesHub.Fixtures alias NervesHub.ManagedDeployments alias NervesHub.Products - alias NervesHub.Support.Fwup - alias NervesHub.Repo + alias NervesHub.Support setup do user = Fixtures.user_fixture() @@ -873,14 +872,19 @@ defmodule NervesHub.DevicesTest do # create some firmware which can be uploaded to each org {:ok, _} = - Fwup.create_firmware(tmp_dir, "old-firmware", %{ + Support.Fwup.create_firmware(tmp_dir, "old-firmware", %{ product: "Same Product Name", fwup_version: "1.13.0" }) # sign and upload for org one {:ok, signed_firmware_one} = - Fwup.sign_firmware(tmp_dir, org_key_one.name, "old-firmware", "old-firmware-signed-one") + Support.Fwup.sign_firmware( + tmp_dir, + org_key_one.name, + "old-firmware", + "old-firmware-signed-one" + ) {:ok, old_firmware_one} = Firmwares.create_firmware(org_one, signed_firmware_one) @@ -890,7 +894,12 @@ defmodule NervesHub.DevicesTest do # sign and upload for org two {:ok, old_signed_firmware_two} = - Fwup.sign_firmware(tmp_dir, org_key_two.name, "old-firmware", "old-firmware-signed-two") + Support.Fwup.sign_firmware( + tmp_dir, + org_key_two.name, + "old-firmware", + "old-firmware-signed-two" + ) {:ok, old_firmware_two} = Firmwares.create_firmware(org_two, old_signed_firmware_two) @@ -900,14 +909,19 @@ defmodule NervesHub.DevicesTest do # and now create some new firmware which can be uploaded to each org {:ok, _} = - Fwup.create_firmware(tmp_dir, "new-firmware", %{ + Support.Fwup.create_firmware(tmp_dir, "new-firmware", %{ product: "Same Product Name", fwup_version: "1.13.0" }) # sign and upload for org one {:ok, new_signed_firmware_one} = - Fwup.sign_firmware(tmp_dir, org_key_one.name, "new-firmware", "new-firmware-signed-one") + Support.Fwup.sign_firmware( + tmp_dir, + org_key_one.name, + "new-firmware", + "new-firmware-signed-one" + ) {:ok, new_firmware_one} = Firmwares.create_firmware(org_one, new_signed_firmware_one) @@ -917,7 +931,12 @@ defmodule NervesHub.DevicesTest do # sign and upload for org two {:ok, new_signed_firmware_two} = - Fwup.sign_firmware(tmp_dir, org_key_two.name, "new-firmware", "new-firmware-signed-two") + Support.Fwup.sign_firmware( + tmp_dir, + org_key_two.name, + "new-firmware", + "new-firmware-signed-two" + ) {:ok, new_firmware_two} = Firmwares.create_firmware(org_two, new_signed_firmware_two) diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex index e5483270f..c838e2b39 100644 --- a/test/support/conn_case.ex +++ b/test/support/conn_case.ex @@ -15,7 +15,7 @@ defmodule NervesHubWeb.ConnCase do use ExUnit.CaseTemplate - alias Ecto.Adapters.SQL.Sandbox + alias Ecto.Adapters.SQL.Sandbox, as: SQLSandbox alias Phoenix.ConnTest using do @@ -34,10 +34,10 @@ defmodule NervesHubWeb.ConnCase do end setup tags do - :ok = Sandbox.checkout(NervesHub.Repo) + :ok = SQLSandbox.checkout(NervesHub.Repo) if !tags[:async] do - Sandbox.mode(NervesHub.Repo, {:shared, self()}) + SQLSandbox.mode(NervesHub.Repo, {:shared, self()}) end {:ok, conn: ConnTest.build_conn()} @@ -61,7 +61,7 @@ defmodule NervesHubWeb.APIConnCase do use ExUnit.CaseTemplate - alias Ecto.Adapters.SQL.Sandbox + alias Ecto.Adapters.SQL.Sandbox, as: SQLSandbox alias NervesHub.Fixtures using do @@ -90,10 +90,10 @@ defmodule NervesHubWeb.APIConnCase do end setup tags do - :ok = Sandbox.checkout(NervesHub.Repo) + :ok = SQLSandbox.checkout(NervesHub.Repo) if !tags[:async] do - Sandbox.mode(NervesHub.Repo, {:shared, self()}) + SQLSandbox.mode(NervesHub.Repo, {:shared, self()}) end user = Fixtures.user_fixture() diff --git a/test/support/data_case.ex b/test/support/data_case.ex index 997fc0149..d0673f5fc 100644 --- a/test/support/data_case.ex +++ b/test/support/data_case.ex @@ -14,7 +14,7 @@ defmodule NervesHub.DataCase do use ExUnit.CaseTemplate - alias Ecto.Adapters.SQL.Sandbox + alias Ecto.Adapters.SQL.Sandbox, as: SQLSandbox using do quote do @@ -33,12 +33,12 @@ defmodule NervesHub.DataCase do end setup tags do - :ok = Sandbox.checkout(NervesHub.Repo) - :ok = Sandbox.checkout(NervesHub.ObanRepo) + :ok = SQLSandbox.checkout(NervesHub.Repo) + :ok = SQLSandbox.checkout(NervesHub.ObanRepo) if !tags[:async] do - Sandbox.mode(NervesHub.Repo, {:shared, self()}) - Sandbox.mode(NervesHub.ObanRepo, {:shared, self()}) + SQLSandbox.mode(NervesHub.Repo, {:shared, self()}) + SQLSandbox.mode(NervesHub.ObanRepo, {:shared, self()}) end :ok From e8e82af704ee41282372ef7cbb6c652b9c3813dc Mon Sep 17 00:00:00 2001 From: Taras Tyshko Date: Wed, 20 Aug 2025 14:24:11 +0300 Subject: [PATCH 10/13] rebase and resolve conflicts, revert macros changes --- lib/nerves_hub_web/api_spec.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nerves_hub_web/api_spec.ex b/lib/nerves_hub_web/api_spec.ex index 064ca14a7..116a0f8c8 100644 --- a/lib/nerves_hub_web/api_spec.ex +++ b/lib/nerves_hub_web/api_spec.ex @@ -12,8 +12,8 @@ defmodule NervesHubWeb.ApiSpec do alias NervesHubWeb.API.OpenAPI.DeviceControllerSpecs alias NervesHubWeb.Endpoint - alias NervesHubWeb.Router alias NervesHubWeb.Plugs.ImAlive + alias NervesHubWeb.Router @behaviour OpenApi From 89c13a5c05671b97d02a01f10826ba036fc1b89e Mon Sep 17 00:00:00 2001 From: Taras Tyshko Date: Wed, 20 Aug 2025 14:33:35 +0300 Subject: [PATCH 11/13] resolve missing comments --- lib/nerves_hub_web/components/core_components.ex | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/nerves_hub_web/components/core_components.ex b/lib/nerves_hub_web/components/core_components.ex index 4061775d2..f7a82d2f6 100644 --- a/lib/nerves_hub_web/components/core_components.ex +++ b/lib/nerves_hub_web/components/core_components.ex @@ -18,7 +18,7 @@ defmodule NervesHubWeb.CoreComponents do import NervesHubWeb.Components.Icons - alias Phoenix.HTML.Form, as: HTMLForm + alias Phoenix.HTML alias Phoenix.LiveView.JS @@ -332,7 +332,7 @@ defmodule NervesHubWeb.CoreComponents do range radio search select tel text textarea time url week) ) - attr(:field, Phoenix.HTML.FormField, doc: "a form field struct retrieved from the form, for example: @form[:email]") + attr(:field, HTML.FormField, doc: "a form field struct retrieved from the form, for example: @form[:email]" ) attr(:errors, :list, default: []) attr(:checked, :boolean, doc: "the checked flag for checkbox inputs") @@ -348,7 +348,7 @@ defmodule NervesHubWeb.CoreComponents do slot(:inner_block) slot(:rich_hint) - def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do + def input(%{field: %HTML.FormField{} = field} = assigns) do assigns |> assign(field: nil, id: assigns.id || field.id) |> assign(:errors, Enum.map(field.errors, &translate_error/1)) @@ -360,7 +360,7 @@ defmodule NervesHubWeb.CoreComponents do def input(%{type: "checkbox"} = assigns) do assigns = assign_new(assigns, :checked, fn -> - HTMLForm.normalize_value("checkbox", assigns[:value]) + HTML.Form.normalize_value("checkbox", assigns[:value]) end) ~H""" @@ -390,7 +390,7 @@ defmodule NervesHubWeb.CoreComponents do {@rest} > - {HTMLForm.options_for_select(@options, @value)} + {HTML.Form.options_for_select(@options, @value)}
{assigns[:hint] || render_slot(assigns[:rich_hint])} @@ -414,7 +414,7 @@ defmodule NervesHubWeb.CoreComponents do @errors != [] && "border-red-500 focus:border-red-500" ]} {@rest} - ><%= HTMLForm.normalize_value("textarea", @value) %> + ><%= HTML.Form.normalize_value("textarea", @value) %>
{assigns[:hint] || render_slot(assigns[:rich_hint])}
@@ -433,7 +433,7 @@ defmodule NervesHubWeb.CoreComponents do type={@type} name={@name} id={@id} - value={HTMLForm.normalize_value(@type, @value)} + value={HTML.Form.normalize_value(@type, @value)} class={[ "mt-2 py-1.5 px-2 block w-full rounded text-zinc-400 bg-zinc-900 focus:ring-0 sm:text-sm", "phx-no-feedback:border-zinc-600 phx-no-feedback:focus:border-zinc-700", @@ -462,7 +462,7 @@ defmodule NervesHubWeb.CoreComponents do type={@type} name={@name} id={@id} - value={HTMLForm.normalize_value(@type, @value)} + value={HTML.Form.normalize_value(@type, @value)} class={[ "mt-2 py-1.5 px-2 block w-full rounded text-zinc-400 bg-zinc-900 focus:ring-0 sm:text-sm", "phx-no-feedback:border-zinc-600 phx-no-feedback:focus:border-zinc-700", From 92f0ef22f11003fd08423ef1f878426f0225f888 Mon Sep 17 00:00:00 2001 From: Taras Tyshko Date: Mon, 1 Sep 2025 12:43:13 +0300 Subject: [PATCH 12/13] git rebase and fix conflicts --- lib/nerves_hub/firmwares/update_tool/fwup.ex | 53 +++++++++---------- .../components/core_components.ex | 2 +- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/lib/nerves_hub/firmwares/update_tool/fwup.ex b/lib/nerves_hub/firmwares/update_tool/fwup.ex index ebb5f71b8..82ef94af5 100644 --- a/lib/nerves_hub/firmwares/update_tool/fwup.ex +++ b/lib/nerves_hub/firmwares/update_tool/fwup.ex @@ -231,51 +231,46 @@ defmodule NervesHub.Firmwares.UpdateTool.Fwup do case File.stat(source_filepath) do {:ok, %{size: f_source_size}} -> - args = [ - "-A", - "-S", - "-f", - "-s", - source_filepath, - target_filepath, - output_path - ] - + args = ["-A", "-S", "-f", "-s", source_filepath, target_filepath, output_path] %{size: f_target_size} = File.stat!(target_filepath) if f_target_size < @delta_overhead_limit do Logger.info("Skipping generating delta for #{path} it is under 22 bytes.") nil else - {_, 0} = System.cmd("xdelta3", args, stderr_to_stdout: true, env: []) - %{size: f_delta_size} = File.stat!(output_path) - - if f_delta_size < f_target_size do - Logger.info( - "Generated delta for #{path}, from #{Float.round(f_source_size / 1024 / 1024, 1)} MB to #{Float.round(f_target_size / 1024 / 1024, 1)} MB via delta of #{Float.round(f_delta_size / 1024 / 1024, 1)} MB" - ) - - output_path - else - Logger.info( - "Skipping generated delta for #{path}, delta is larger: #{Float.round(f_source_size / 1024 / 1024, 1)} MB to #{Float.round(f_target_size / 1024 / 1024, 1)} MB via delta of #{Float.round(f_delta_size / 1024 / 1024, 1)} MB" - ) - - nil - end + generate_and_validate_delta(path, args, output_path, f_source_size, f_target_size) end {:error, :enoent} -> nil end + else + nil + end + end + + defp generate_and_validate_delta(path, args, output_path, f_source_size, f_target_size) do + {_, 0} = System.cmd("xdelta3", args, stderr_to_stdout: true, env: %{}) + %{size: f_delta_size} = File.stat!(output_path) + + if f_delta_size < f_target_size do + Logger.info( + "Generated delta for #{path}, from #{Float.round(f_source_size / 1024 / 1024, 1)} MB to #{Float.round(f_target_size / 1024 / 1024, 1)} MB via delta of #{Float.round(f_delta_size / 1024 / 1024, 1)} MB" + ) + + output_path + else + Logger.info( + "Skipping generated delta for #{path}, delta is larger: #{Float.round(f_source_size / 1024 / 1024, 1)} MB to #{Float.round(f_target_size / 1024 / 1024, 1)} MB via delta of #{Float.round(f_delta_size / 1024 / 1024, 1)} MB" + ) + + nil end end defp delta_files(deltas) do deltas - |> Enum.flat_map(fn {_k, files} -> - files - end) + |> Enum.flat_map(fn {_k, files} -> files end) |> Enum.uniq() |> case do [] -> {:error, :no_delta_support_in_firmware} diff --git a/lib/nerves_hub_web/components/core_components.ex b/lib/nerves_hub_web/components/core_components.ex index f7a82d2f6..17d6edec0 100644 --- a/lib/nerves_hub_web/components/core_components.ex +++ b/lib/nerves_hub_web/components/core_components.ex @@ -332,7 +332,7 @@ defmodule NervesHubWeb.CoreComponents do range radio search select tel text textarea time url week) ) - attr(:field, HTML.FormField, doc: "a form field struct retrieved from the form, for example: @form[:email]" ) + attr(:field, HTML.FormField, doc: "a form field struct retrieved from the form, for example: @form[:email]") attr(:errors, :list, default: []) attr(:checked, :boolean, doc: "the checked flag for checkbox inputs") From 63461e7699217109ebfeee684e72c9338cb64c3b Mon Sep 17 00:00:00 2001 From: Taras Tyshko Date: Thu, 11 Sep 2025 15:39:51 +0300 Subject: [PATCH 13/13] Rebase main --- lib/nerves_hub/firmwares/update_tool/fwup.ex | 2 -- lib/nerves_hub_web/channels/device_json_serializer.ex | 8 +++++--- test/nerves_hub_web/channels/websocket_test.exs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/nerves_hub/firmwares/update_tool/fwup.ex b/lib/nerves_hub/firmwares/update_tool/fwup.ex index 82ef94af5..b6d6c25cf 100644 --- a/lib/nerves_hub/firmwares/update_tool/fwup.ex +++ b/lib/nerves_hub/firmwares/update_tool/fwup.ex @@ -244,8 +244,6 @@ defmodule NervesHub.Firmwares.UpdateTool.Fwup do {:error, :enoent} -> nil end - else - nil end end diff --git a/lib/nerves_hub_web/channels/device_json_serializer.ex b/lib/nerves_hub_web/channels/device_json_serializer.ex index 4ab3efd68..e62620c10 100644 --- a/lib/nerves_hub_web/channels/device_json_serializer.ex +++ b/lib/nerves_hub_web/channels/device_json_serializer.ex @@ -16,25 +16,27 @@ defmodule NervesHubWeb.Channels.DeviceJSONSerializer do `device:[device_id]` => `device` """ + alias Phoenix.Socket.V2.JSONSerializer + @behaviour Phoenix.Socket.Serializer @impl Phoenix.Socket.Serializer def fastlane!(msg) do msg |> remove_device_id_from_topic() - |> Phoenix.Socket.V2.JSONSerializer.fastlane!() + |> JSONSerializer.fastlane!() end @impl Phoenix.Socket.Serializer def encode!(reply) do reply |> remove_device_id_from_topic() - |> Phoenix.Socket.V2.JSONSerializer.encode!() + |> JSONSerializer.encode!() end @impl Phoenix.Socket.Serializer def decode!(raw_message, opts) do - Phoenix.Socket.V2.JSONSerializer.decode!(raw_message, opts) + JSONSerializer.decode!(raw_message, opts) |> add_device_id_to_topic() end diff --git a/test/nerves_hub_web/channels/websocket_test.exs b/test/nerves_hub_web/channels/websocket_test.exs index 713ae3b55..da872f72f 100644 --- a/test/nerves_hub_web/channels/websocket_test.exs +++ b/test/nerves_hub_web/channels/websocket_test.exs @@ -1003,7 +1003,7 @@ defmodule NervesHubWeb.WebsocketTest do not_before = DateTime.utc_now() |> Timex.shift(days: -1) not_after = DateTime.utc_now() |> Timex.shift(seconds: 1) - template = X509Template.new(:root_ca, validity: X509.Validity.new(not_before, not_after)) + template = X509Template.new(:root_ca, validity: X509Validity.new(not_before, not_after)) %{cert: ca, key: ca_key} = Fixtures.ca_certificate_fixture(org, template: template)