From bad5781bca09c0afdfe95d744072135c15209d55 Mon Sep 17 00:00:00 2001 From: Elin Olsson Date: Wed, 18 Dec 2024 13:27:57 +0100 Subject: [PATCH 1/8] move all AuditLog.audit! calls to templates --- lib/nerves_hub/audit_logs/templates.ex | 107 ++++++++++++++++-- lib/nerves_hub/deployments.ex | 18 +-- lib/nerves_hub/devices.ex | 26 +---- .../controllers/api/deployment_controller.ex | 14 +-- .../controllers/api/device_controller.ex | 10 +- lib/nerves_hub_web/live/deployments/edit.ex | 8 +- lib/nerves_hub_web/live/deployments/new.ex | 8 +- lib/nerves_hub_web/live/deployments/show.ex | 10 +- lib/nerves_hub_web/live/devices/index.ex | 4 +- lib/nerves_hub_web/live/devices/show.ex | 26 +---- 10 files changed, 131 insertions(+), 100 deletions(-) diff --git a/lib/nerves_hub/audit_logs/templates.ex b/lib/nerves_hub/audit_logs/templates.ex index 0215e26a0..5a140feed 100644 --- a/lib/nerves_hub/audit_logs/templates.ex +++ b/lib/nerves_hub/audit_logs/templates.ex @@ -7,6 +7,38 @@ defmodule NervesHub.AuditLogs.Templates do require Logger + ### RESOURCE: DEVICE + + ## General + + def audit_reboot(user, device) do + description = "#{user.name} rebooted device #{device.identifier}" + AuditLogs.audit!(user, device, description) + end + + def audit_request_action(user, device, action) do + description = "#{user.name} requested the device (#{device.identifier}) #{action}" + AuditLogs.audit!(user, device, description) + end + + def audit_unsupported_api_version(device) do + description = + "device #{device.identifier} could not get extensions: Unsupported API version." + + AuditLogs.audit!(device, device, description) + Logger.info("[DeviceChannel] #{description}") + end + + ## Firmware and upgrades + # Deprecated? + def audit_device_assigned(device, reference_id) do + description = + "device #{device.identifier} reloaded deployment and is attached to deployment #{device.deployment.name}" + + AuditLogs.audit_with_ref!(device, device, description, reference_id) + end + + # Deprecated? def audit_resolve_changed_deployment(device, reference_id) do description = if device.deployment_id do @@ -18,6 +50,46 @@ defmodule NervesHub.AuditLogs.Templates do AuditLogs.audit_with_ref!(device, device, description, reference_id) end + def audit_update_attempt(device) do + description = "device #{device.identifier} is attempting to update" + AuditLogs.audit(device, device, description) + end + + def audit_pushed_available_update(user, device, deployment) do + description = + "#{user.name} pushed available firmware update #{deployment.firmware.version} #{deployment.firmware.uuid} to device #{device.identifier}" + + AuditLogs.audit!(user, device, description) + end + + def audit_firmware_pushed(user, device, firmware) do + description = + "#{user.name} pushed firmware #{firmware.version} #{firmware.uuid} to device #{device.identifier}" + + AuditLogs.audit!(user, device, description) + end + + def audit_firmware_metadata_updated(device) do + description = "device #{device.identifier} updated firmware metadata" + AuditLogs.audit!(device, device, description) + end + + def audit_firmware_upgrade_blocked(deployment, device) do + description = """ + Device #{device.identifier} automatically blocked firmware upgrades for #{deployment.penalty_timeout_minutes} minutes. + Device failure rate met for firmware #{deployment.firmware.uuid} in deployment #{deployment.name}. + """ + + AuditLogs.audit!(deployment, device, description) + end + + def audit_firmware_updated(device) do + description = + "device #{device.identifier} firmware set to version #{device.firmware_metadata.version} (#{device.firmware_metadata.uuid})" + + AuditLogs.audit!(device, device, description) + end + def audit_device_deployment_update_triggered(device, reference_id) do deployment = device.deployment firmware = deployment.firmware @@ -28,19 +100,38 @@ defmodule NervesHub.AuditLogs.Templates do AuditLogs.audit_with_ref!(deployment, device, description, reference_id) end - def audit_device_assigned(device, reference_id) do - description = - "device #{device.identifier} reloaded deployment and is attached to deployment #{device.deployment.name}" + ### RESOUCE: DEPLOYMENT - AuditLogs.audit_with_ref!(device, device, description, reference_id) + def audit_deployment_created(user, deployment) do + description = "#{user.name} created deployment #{deployment.name}" + AuditLogs.audit!(user, deployment, description) end - def audit_unsupported_api_version(device) do + def audit_deployment_updated(user, deployment) do + description = "#{user.name} updated deployment #{deployment.name}" + AuditLogs.audit!(user, deployment, description) + end + + def audit_deployment_deleted(user, deployment) do + description = "#{user.name} deleted deployment #{deployment.name}" + AuditLogs.audit!(user, deployment, description) + end + + def audit_deployment_toggle_active(user, deployment, status) do + description = "#{user.name} marked deployment #{deployment.name} #{status}" + AuditLogs.audit!(user, deployment, description) + end + + def audit_deployment_mismatch(device, deployment, reason) do description = - "device #{device.identifier} could not get extensions: Unsupported API version." + "device no longer matches deployment #{deployment.name}'s requirements because of #{reason}" - AuditLogs.audit!(device, device, description) - Logger.info("[DeviceChannel] #{description}") + AuditLogs.audit!(device, deployment, description) + end + + def audit_deployment_change(deployment, change_string) do + description = "deployment #{deployment.name} #{change_string}" + AuditLogs.audit!(deployment, deployment, description) end @spec audit_device_deployment_update(User.t(), Device.t(), Deployment.t()) :: AuditLog.t() diff --git a/lib/nerves_hub/deployments.ex b/lib/nerves_hub/deployments.ex index ed50ba733..01ceb0741 100644 --- a/lib/nerves_hub/deployments.ex +++ b/lib/nerves_hub/deployments.ex @@ -3,7 +3,6 @@ defmodule NervesHub.Deployments do require Logger - alias NervesHub.AuditLogs alias NervesHub.AuditLogs.Templates alias NervesHub.Deployments.Deployment alias NervesHub.Deployments.InflightDeploymentCheck @@ -186,16 +185,13 @@ defmodule NervesHub.Deployments do payload = %{archive_id: archive_id} _ = broadcast(deployment, "archives/updated", payload) - description = "deployment #{deployment.name} has a new archive" - AuditLogs.audit!(deployment, deployment, description) + Templates.audit_deployment_change(deployment, "has a new archive") {:conditions, _new_conditions} -> - description = "deployment #{deployment.name} conditions changed" - AuditLogs.audit!(deployment, deployment, description) + Templates.audit_deployment_change(deployment, "conditions changed") {:is_active, is_active} when is_active != true -> - description = "deployment #{deployment.name} is inactive" - AuditLogs.audit!(deployment, deployment, description) + Templates.audit_deployment_change(deployment, "is inactive") _ -> :ignore @@ -338,13 +334,7 @@ defmodule NervesHub.Deployments do |> Ecto.Changeset.change(%{deployment_id: nil}) |> Repo.update!() - AuditLogs.audit!( - device, - device, - "device no longer matches deployment #{deployment.name}'s requirements because of #{reason}" - ) - - device + Templates.audit_deployment_mismatch(device, deployment, reason) else device end diff --git a/lib/nerves_hub/devices.ex b/lib/nerves_hub/devices.ex index 5ace2bb2c..bb3432386 100644 --- a/lib/nerves_hub/devices.ex +++ b/lib/nerves_hub/devices.ex @@ -8,6 +8,7 @@ defmodule NervesHub.Devices do alias NervesHub.Accounts.OrgKey alias NervesHub.Accounts.User alias NervesHub.AuditLogs + alias NervesHub.AuditLogs.Templates alias NervesHub.Certificate alias NervesHub.Deployments.Deployment alias NervesHub.Deployments.Orchestrator @@ -681,8 +682,7 @@ defmodule NervesHub.Devices do end def update_firmware_metadata(device, metadata) do - description = "Device #{device.identifier} updated firmware metadata" - AuditLogs.audit!(device, device, description) + Templates.audit_firmware_metadata_updated(device) update_device(device, %{firmware_metadata: metadata}) end @@ -840,12 +840,7 @@ defmodule NervesHub.Devices do |> DateTime.truncate(:second) |> DateTime.add(deployment.penalty_timeout_minutes * 60, :second) - description = """ - Device #{device.identifier} automatically blocked firmware upgrades for #{deployment.penalty_timeout_minutes} minutes. - Device failure rate met for firmware #{deployment.firmware.uuid} in deployment #{deployment.name}. - """ - - AuditLogs.audit!(deployment, device, description) + Templates.audit_firmware_upgrade_blocked(deployment, device) clear_inflight_update(device) {:ok, device} = update_device(device, %{updates_blocked_until: blocked_until}) @@ -858,12 +853,7 @@ defmodule NervesHub.Devices do |> DateTime.truncate(:second) |> DateTime.add(deployment.penalty_timeout_minutes * 60, :second) - description = """ - Device #{device.identifier} automatically blocked firmware upgrades for #{deployment.penalty_timeout_minutes} minutes. - Device failure threshold met for firmware #{deployment.firmware.uuid} in deployment #{deployment.name}. - """ - - AuditLogs.audit!(deployment, device, description) + Templates.audit_firmware_upgrade_blocked(deployment, device) clear_inflight_update(device) {:ok, device} = update_device(device, %{updates_blocked_until: blocked_until}) @@ -886,8 +876,7 @@ defmodule NervesHub.Devices do Multi.new() |> Multi.update(:device, changeset) |> Multi.run(:audit_device, fn _, _ -> - description = "device #{device.identifier} is attempting to update" - AuditLogs.audit(device, device, description) + Templates.audit_update_attempt(device) end) |> Repo.transaction() |> case do @@ -905,10 +894,7 @@ defmodule NervesHub.Devices do firmware_uuid: device.firmware_metadata.uuid }) - description = - "Device #{device.identifier} firmware set to version #{device.firmware_metadata.version} (#{device.firmware_metadata.uuid})" - - AuditLogs.audit!(device, device, description) + Templates.audit_firmware_updated(device) # Clear the inflight update, no longer inflight! inflight_update = diff --git a/lib/nerves_hub_web/controllers/api/deployment_controller.ex b/lib/nerves_hub_web/controllers/api/deployment_controller.ex index bb5377a44..3759b716f 100644 --- a/lib/nerves_hub_web/controllers/api/deployment_controller.ex +++ b/lib/nerves_hub_web/controllers/api/deployment_controller.ex @@ -1,7 +1,7 @@ defmodule NervesHubWeb.API.DeploymentController do use NervesHubWeb, :api_controller - alias NervesHub.AuditLogs + alias NervesHub.AuditLogs.Templates alias NervesHub.Deployments alias NervesHub.Deployments.Deployment alias NervesHub.Firmwares @@ -29,11 +29,7 @@ defmodule NervesHubWeb.API.DeploymentController do params <- Map.put(params, "org_id", org.id), params <- whitelist(params, @whitelist_fields), {:ok, deployment} <- Deployments.create_deployment(params) do - AuditLogs.audit!( - user, - deployment, - "#{user.name} created deployment #{deployment.name}" - ) + Templates.audit_deployment_created(user, deployment) conn |> put_status(:created) @@ -61,11 +57,7 @@ defmodule NervesHubWeb.API.DeploymentController do deployment_params <- whitelist(deployment_params, @whitelist_fields), {:ok, %Deployment{} = updated_deployment} <- Deployments.update_deployment(deployment, deployment_params) do - AuditLogs.audit!( - user, - deployment, - "#{user.name} updated deployment #{deployment.name}" - ) + Templates.audit_deployment_updated(user, deployment) render(conn, "show.json", deployment: updated_deployment) end diff --git a/lib/nerves_hub_web/controllers/api/device_controller.ex b/lib/nerves_hub_web/controllers/api/device_controller.ex index c1696f89e..42dfda127 100644 --- a/lib/nerves_hub_web/controllers/api/device_controller.ex +++ b/lib/nerves_hub_web/controllers/api/device_controller.ex @@ -2,7 +2,7 @@ defmodule NervesHubWeb.API.DeviceController do use NervesHubWeb, :api_controller alias NervesHub.Accounts - alias NervesHub.AuditLogs + alias NervesHub.AuditLogs.Templates alias NervesHub.Devices alias NervesHub.Devices.DeviceCertificate alias NervesHub.Devices.UpdatePayload @@ -117,8 +117,7 @@ defmodule NervesHubWeb.API.DeviceController do case Devices.get_by_identifier(identifier) do {:ok, device} -> if Accounts.has_org_role?(device.org, user, :manage) do - message = "#{user.name} rebooted device #{device.identifier}" - AuditLogs.audit!(user, device, message) + Templates.audit_reboot(user, device) _ = Endpoint.broadcast_from(self(), "device:#{device.id}", "reboot", %{}) @@ -205,10 +204,7 @@ defmodule NervesHubWeb.API.DeviceController do {:ok, device} = Devices.disable_updates(device, user) device = Repo.preload(device, [:device_certificates]) - description = - "User #{user.name} pushed firmware #{firmware.version} #{firmware.uuid} to device #{device.identifier}" - - AuditLogs.audit!(user, device, description) + Templates.audit_firmware_pushed(user, device, firmware) payload = %UpdatePayload{ update_available: true, diff --git a/lib/nerves_hub_web/live/deployments/edit.ex b/lib/nerves_hub_web/live/deployments/edit.ex index 4ed8fd17f..a04cdb57f 100644 --- a/lib/nerves_hub_web/live/deployments/edit.ex +++ b/lib/nerves_hub_web/live/deployments/edit.ex @@ -2,7 +2,7 @@ defmodule NervesHubWeb.Live.Deployments.Edit do use NervesHubWeb, :updated_live_view alias NervesHub.Archives - alias NervesHub.AuditLogs + alias NervesHub.AuditLogs.Templates alias NervesHub.Deployments alias NervesHub.Deployments.Deployment alias NervesHub.Firmwares @@ -46,11 +46,7 @@ defmodule NervesHubWeb.Live.Deployments.Edit do {:ok, updated} -> # Use original deployment so changes will get # marked in audit log - AuditLogs.audit!( - user, - updated, - "#{user.name} updated deployment #{updated.name}" - ) + Templates.audit_deployment_updated(user, updated) socket |> put_flash(:info, "Deployment updated") diff --git a/lib/nerves_hub_web/live/deployments/new.ex b/lib/nerves_hub_web/live/deployments/new.ex index da8f3fdf9..0ae16c680 100644 --- a/lib/nerves_hub_web/live/deployments/new.ex +++ b/lib/nerves_hub_web/live/deployments/new.ex @@ -1,7 +1,7 @@ defmodule NervesHubWeb.Live.Deployments.New do use NervesHubWeb, :updated_live_view - alias NervesHub.AuditLogs + alias NervesHub.AuditLogs.Templates alias NervesHub.Deployments alias NervesHub.Deployments.Deployment alias NervesHub.Firmwares @@ -81,11 +81,7 @@ defmodule NervesHubWeb.Live.Deployments.New do |> noreply() {_, {:ok, deployment}} -> - AuditLogs.audit!( - user, - deployment, - "#{user.name} created deployment #{deployment.name}" - ) + Templates.audit_deployment_created(user, deployment) socket |> put_flash(:info, "Deployment created") diff --git a/lib/nerves_hub_web/live/deployments/show.ex b/lib/nerves_hub_web/live/deployments/show.ex index 49cf78375..aa6f3e473 100644 --- a/lib/nerves_hub_web/live/deployments/show.ex +++ b/lib/nerves_hub_web/live/deployments/show.ex @@ -2,6 +2,7 @@ defmodule NervesHubWeb.Live.Deployments.Show do use NervesHubWeb, :updated_live_view alias NervesHub.AuditLogs + alias NervesHub.AuditLogs.Templates alias NervesHub.Deployments alias NervesHub.Deployments.Deployment alias NervesHub.Devices @@ -64,8 +65,7 @@ defmodule NervesHubWeb.Live.Deployments.Show do {:ok, deployment} = Deployments.update_deployment(deployment, %{is_active: value}) active_str = if value, do: "active", else: "inactive" - description = "#{user.name} marked deployment #{deployment.name} #{active_str}" - AuditLogs.audit!(user, deployment, description) + Templates.audit_deployment_toggle_active(user, deployment, active_str) socket |> put_flash(:info, "Deployment set #{active_str}") @@ -78,12 +78,10 @@ defmodule NervesHubWeb.Live.Deployments.Show do %{deployment: deployment, org: org, product: product, user: user} = socket.assigns - description = "#{user.name} deleted deployment #{deployment.name}" - - AuditLogs.audit!(user, deployment, description) - {:ok, _} = Deployments.delete_deployment(deployment) + Templates.audit_deployment_deleted(user, deployment) + socket |> put_flash(:info, "Deployment successfully deleted") |> push_navigate(to: ~p"/org/#{org.name}/#{product.name}/deployments") diff --git a/lib/nerves_hub_web/live/devices/index.ex b/lib/nerves_hub_web/live/devices/index.ex index b495db4ae..48ac7daa3 100644 --- a/lib/nerves_hub_web/live/devices/index.ex +++ b/lib/nerves_hub_web/live/devices/index.ex @@ -5,7 +5,7 @@ defmodule NervesHubWeb.Live.Devices.Index do require OpenTelemetry.Tracer, as: Tracer - alias NervesHub.AuditLogs + alias NervesHub.AuditLogs.Templates alias NervesHub.Devices alias NervesHub.Devices.Alarms alias NervesHub.Devices.Metrics @@ -373,7 +373,7 @@ defmodule NervesHubWeb.Live.Devices.Index do {:ok, device} = Devices.get_device_by_identifier(org, device_identifier) - AuditLogs.audit!(user, device, "#{user.name} rebooted device #{device.identifier}") + Templates.audit_reboot(user, device) socket.endpoint.broadcast_from(self(), "device:#{device.id}", "reboot", %{}) diff --git a/lib/nerves_hub_web/live/devices/show.ex b/lib/nerves_hub_web/live/devices/show.ex index a8f82eec1..47cc490da 100644 --- a/lib/nerves_hub_web/live/devices/show.ex +++ b/lib/nerves_hub_web/live/devices/show.ex @@ -191,7 +191,7 @@ defmodule NervesHubWeb.Live.Devices.Show do authorized!(:"device:reboot", org_user) - AuditLogs.audit!(user, device, "#{user.name} rebooted device #{device.identifier}") + Templates.audit_reboot(user, device) socket.endpoint.broadcast_from(self(), "device:#{device.id}", "reboot", %{}) @@ -203,11 +203,7 @@ defmodule NervesHubWeb.Live.Devices.Show do authorized!(:"device:reconnect", org_user) - AuditLogs.audit!( - user, - device, - "User #{user.name} requested the device (#{device.identifier}) reconnect" - ) + Templates.audit_request_action(user, device, "reconnect") socket.endpoint.broadcast("device_socket:#{device.id}", "disconnect", %{}) @@ -219,11 +215,7 @@ defmodule NervesHubWeb.Live.Devices.Show do authorized!(:"device:identify", org_user) - AuditLogs.audit!( - user, - device, - "User #{user.name} requested the device (#{device.identifier}) identify itself" - ) + Templates.audit_request_action(user, device, "identify itself") socket.endpoint.broadcast_from(self(), "device:#{socket.assigns.device.id}", "identify", %{}) @@ -338,10 +330,7 @@ defmodule NervesHubWeb.Live.Devices.Show do {:ok, meta} = Firmwares.metadata_from_firmware(firmware) {:ok, device} = Devices.disable_updates(device, user) - description = - "User #{user.name} pushed firmware #{firmware.version} #{firmware.uuid} to device #{device.identifier}" - - AuditLogs.audit!(user, device, description) + Templates.audit_firmware_pushed(user, device, firmware) payload = %UpdatePayload{ update_available: true, @@ -364,13 +353,10 @@ defmodule NervesHubWeb.Live.Devices.Show do deployment = NervesHub.Repo.preload(deployment, :firmware) - description = - "#{user.name} pushed available firmware update #{deployment.firmware.version} #{deployment.firmware.uuid} to device #{device.identifier}" - - AuditLogs.audit!(user, device, description) - case Devices.told_to_update(device, deployment) do {:ok, inflight_update} -> + Templates.audit_pushed_available_update(user, device, deployment) + _ = NervesHubWeb.Endpoint.broadcast( "device:#{device.id}", From 1bab50a1888d3e86a8c17cec9ab6c6cb8d41113a Mon Sep 17 00:00:00 2001 From: Elin Olsson Date: Sat, 28 Dec 2024 19:24:37 +0100 Subject: [PATCH 2/8] Move device move audits to templates --- lib/nerves_hub/audit_logs/templates.ex | 22 +++++++++++++++++++++- lib/nerves_hub/devices.ex | 16 +++++----------- lib/nerves_hub_web/live/devices/index.ex | 10 ++++++++-- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/lib/nerves_hub/audit_logs/templates.ex b/lib/nerves_hub/audit_logs/templates.ex index 5a140feed..f2c0ff459 100644 --- a/lib/nerves_hub/audit_logs/templates.ex +++ b/lib/nerves_hub/audit_logs/templates.ex @@ -4,6 +4,7 @@ defmodule NervesHub.AuditLogs.Templates do alias NervesHub.AuditLogs.AuditLog alias NervesHub.Deployments.Deployment alias NervesHub.Devices.Device + alias NervesHub.Repo require Logger @@ -16,6 +17,25 @@ defmodule NervesHub.AuditLogs.Templates do AuditLogs.audit!(user, device, description) end + @doc """ + Creates audit log entries for device, target product and source product on device move. + Rollbacks on failure. + """ + def audit_device_moved(user, device, target_product, source_product) do + description = + "user #{user.name} moved device #{device.identifier} to #{target_product.org.name} : #{target_product.name}" + + Repo.transaction(fn -> + AuditLogs.audit(user, device, description) + AuditLogs.audit(user, target_product, description) + AuditLogs.audit(user, source_product, description) + end) + |> case do + {:ok, result} -> result + {:error, error} -> Repo.rollback(error) + end + end + def audit_request_action(user, device, action) do description = "#{user.name} requested the device (#{device.identifier}) #{action}" AuditLogs.audit!(user, device, description) @@ -100,7 +120,7 @@ defmodule NervesHub.AuditLogs.Templates do AuditLogs.audit_with_ref!(deployment, device, description, reference_id) end - ### RESOUCE: DEPLOYMENT + ### RESOURCE: DEPLOYMENT def audit_deployment_created(user, deployment) do description = "#{user.name} created deployment #{deployment.name}" diff --git a/lib/nerves_hub/devices.ex b/lib/nerves_hub/devices.ex index bb3432386..c8eb13ad5 100644 --- a/lib/nerves_hub/devices.ex +++ b/lib/nerves_hub/devices.ex @@ -30,6 +30,8 @@ defmodule NervesHub.Devices do alias NervesHub.Repo alias NervesHub.TaskSupervisor, as: Tasks + require Logger + @min_fwup_delta_updatable_version ">=1.10.0" def get_device(device_id) when is_integer(device_id) do @@ -949,9 +951,6 @@ defmodule NervesHub.Devices do _ = maybe_copy_firmware_keys(device, product.org) - description = - "user #{user.name} moved device #{device.identifier} to #{product.org.name} : #{product.name}" - source_product = %Product{ id: device.product_id, org_id: device.org_id @@ -959,14 +958,8 @@ defmodule NervesHub.Devices do Multi.new() |> Multi.run(:move, fn _, _ -> update_device(device, attrs) end) - |> Multi.run(:audit_device, fn _, _ -> - AuditLogs.audit(user, device, description) - end) - |> Multi.run(:audit_target, fn _, _ -> - AuditLogs.audit(user, product, description) - end) - |> Multi.run(:audit_source, fn _, _ -> - AuditLogs.audit(user, source_product, description) + |> Multi.run(:audit, fn _, _ -> + Templates.audit_device_moved(user, device, product, source_product) end) |> Repo.transaction() |> case do @@ -975,6 +968,7 @@ defmodule NervesHub.Devices do {:ok, updated} err -> + Logger.warning("Could not move device: #{inspect(err)}") err end end diff --git a/lib/nerves_hub_web/live/devices/index.ex b/lib/nerves_hub_web/live/devices/index.ex index 48ac7daa3..69ab5c963 100644 --- a/lib/nerves_hub_web/live/devices/index.ex +++ b/lib/nerves_hub_web/live/devices/index.ex @@ -290,7 +290,7 @@ defmodule NervesHubWeb.Live.Devices.Index do end def handle_event("move-devices-product", _, socket) do - %{ok: successfuls} = + %{ok: successfuls, error: errors} = Devices.get_devices_by_id(socket.assigns.selected_devices) |> Devices.move_many(socket.assigns.target_product, socket.assigns.user) @@ -303,7 +303,13 @@ defmodule NervesHubWeb.Live.Devices.Index do |> assign_display_devices() |> assign(:target_product, nil) - {:noreply, socket} + case length(errors) do + 0 -> + {:noreply, socket} + + num -> + {:noreply, put_flash(socket, :error, "Could not move #{num} device(s)")} + end end def handle_event( From 5c5d09177d093ef4d5bd49aea4aa34dc0d5ad3fc Mon Sep 17 00:00:00 2001 From: Elin Olsson Date: Tue, 14 Jan 2025 08:47:00 +0100 Subject: [PATCH 3/8] Revert "Move device move audits to templates" This reverts commit ca603f757ccaab050a7a621885dce8a6684b138c. --- lib/nerves_hub/audit_logs/templates.ex | 22 +--------------------- lib/nerves_hub/devices.ex | 16 +++++++++++----- lib/nerves_hub_web/live/devices/index.ex | 10 ++-------- 3 files changed, 14 insertions(+), 34 deletions(-) diff --git a/lib/nerves_hub/audit_logs/templates.ex b/lib/nerves_hub/audit_logs/templates.ex index f2c0ff459..5a140feed 100644 --- a/lib/nerves_hub/audit_logs/templates.ex +++ b/lib/nerves_hub/audit_logs/templates.ex @@ -4,7 +4,6 @@ defmodule NervesHub.AuditLogs.Templates do alias NervesHub.AuditLogs.AuditLog alias NervesHub.Deployments.Deployment alias NervesHub.Devices.Device - alias NervesHub.Repo require Logger @@ -17,25 +16,6 @@ defmodule NervesHub.AuditLogs.Templates do AuditLogs.audit!(user, device, description) end - @doc """ - Creates audit log entries for device, target product and source product on device move. - Rollbacks on failure. - """ - def audit_device_moved(user, device, target_product, source_product) do - description = - "user #{user.name} moved device #{device.identifier} to #{target_product.org.name} : #{target_product.name}" - - Repo.transaction(fn -> - AuditLogs.audit(user, device, description) - AuditLogs.audit(user, target_product, description) - AuditLogs.audit(user, source_product, description) - end) - |> case do - {:ok, result} -> result - {:error, error} -> Repo.rollback(error) - end - end - def audit_request_action(user, device, action) do description = "#{user.name} requested the device (#{device.identifier}) #{action}" AuditLogs.audit!(user, device, description) @@ -120,7 +100,7 @@ defmodule NervesHub.AuditLogs.Templates do AuditLogs.audit_with_ref!(deployment, device, description, reference_id) end - ### RESOURCE: DEPLOYMENT + ### RESOUCE: DEPLOYMENT def audit_deployment_created(user, deployment) do description = "#{user.name} created deployment #{deployment.name}" diff --git a/lib/nerves_hub/devices.ex b/lib/nerves_hub/devices.ex index c8eb13ad5..bb3432386 100644 --- a/lib/nerves_hub/devices.ex +++ b/lib/nerves_hub/devices.ex @@ -30,8 +30,6 @@ defmodule NervesHub.Devices do alias NervesHub.Repo alias NervesHub.TaskSupervisor, as: Tasks - require Logger - @min_fwup_delta_updatable_version ">=1.10.0" def get_device(device_id) when is_integer(device_id) do @@ -951,6 +949,9 @@ defmodule NervesHub.Devices do _ = maybe_copy_firmware_keys(device, product.org) + description = + "user #{user.name} moved device #{device.identifier} to #{product.org.name} : #{product.name}" + source_product = %Product{ id: device.product_id, org_id: device.org_id @@ -958,8 +959,14 @@ defmodule NervesHub.Devices do Multi.new() |> Multi.run(:move, fn _, _ -> update_device(device, attrs) end) - |> Multi.run(:audit, fn _, _ -> - Templates.audit_device_moved(user, device, product, source_product) + |> Multi.run(:audit_device, fn _, _ -> + AuditLogs.audit(user, device, description) + end) + |> Multi.run(:audit_target, fn _, _ -> + AuditLogs.audit(user, product, description) + end) + |> Multi.run(:audit_source, fn _, _ -> + AuditLogs.audit(user, source_product, description) end) |> Repo.transaction() |> case do @@ -968,7 +975,6 @@ defmodule NervesHub.Devices do {:ok, updated} err -> - Logger.warning("Could not move device: #{inspect(err)}") err end end diff --git a/lib/nerves_hub_web/live/devices/index.ex b/lib/nerves_hub_web/live/devices/index.ex index 69ab5c963..48ac7daa3 100644 --- a/lib/nerves_hub_web/live/devices/index.ex +++ b/lib/nerves_hub_web/live/devices/index.ex @@ -290,7 +290,7 @@ defmodule NervesHubWeb.Live.Devices.Index do end def handle_event("move-devices-product", _, socket) do - %{ok: successfuls, error: errors} = + %{ok: successfuls} = Devices.get_devices_by_id(socket.assigns.selected_devices) |> Devices.move_many(socket.assigns.target_product, socket.assigns.user) @@ -303,13 +303,7 @@ defmodule NervesHubWeb.Live.Devices.Index do |> assign_display_devices() |> assign(:target_product, nil) - case length(errors) do - 0 -> - {:noreply, socket} - - num -> - {:noreply, put_flash(socket, :error, "Could not move #{num} device(s)")} - end + {:noreply, socket} end def handle_event( From 345e54636ea9f677c786de846f49df0d88e1eae3 Mon Sep 17 00:00:00 2001 From: Elin Olsson Date: Tue, 14 Jan 2025 10:27:12 +0100 Subject: [PATCH 4/8] Split templates out in submodules for devices and deployments Add moduledocs and function specs. --- .../templates/deployment_templates.ex | 47 ++++++++++++++++ .../device_templates.ex} | 54 ++++++------------- lib/nerves_hub/deployments.ex | 15 +++--- lib/nerves_hub/devices.ex | 12 ++--- lib/nerves_hub_web/channels/device_channel.ex | 9 ++-- .../controllers/api/deployment_controller.ex | 6 +-- .../controllers/api/device_controller.ex | 6 +-- lib/nerves_hub_web/live/deployments/edit.ex | 4 +- lib/nerves_hub_web/live/deployments/new.ex | 4 +- lib/nerves_hub_web/live/deployments/show.ex | 6 +-- lib/nerves_hub_web/live/devices/index.ex | 4 +- lib/nerves_hub_web/live/devices/show.ex | 14 ++--- 12 files changed, 106 insertions(+), 75 deletions(-) create mode 100644 lib/nerves_hub/audit_logs/templates/deployment_templates.ex rename lib/nerves_hub/audit_logs/{templates.ex => templates/device_templates.ex} (77%) diff --git a/lib/nerves_hub/audit_logs/templates/deployment_templates.ex b/lib/nerves_hub/audit_logs/templates/deployment_templates.ex new file mode 100644 index 000000000..84bd8df12 --- /dev/null +++ b/lib/nerves_hub/audit_logs/templates/deployment_templates.ex @@ -0,0 +1,47 @@ +defmodule NervesHub.AuditLogs.DeploymentTemplates do + @moduledoc """ + Templates for and handling of audit logging for deployment operations. + """ + alias NervesHub.Accounts.User + alias NervesHub.AuditLogs + alias NervesHub.AuditLogs.AuditLog + alias NervesHub.Deployments.Deployment + + @spec audit_deployment_created(User.t(), Deployment.t()) :: AuditLog.t() + def audit_deployment_created(user, deployment) do + description = "#{user.name} created deployment #{deployment.name}" + AuditLogs.audit!(user, deployment, description) + end + + @spec audit_deployment_updated(User.t(), Deployment.t()) :: AuditLog.t() + def audit_deployment_updated(user, deployment) do + description = "#{user.name} updated deployment #{deployment.name}" + AuditLogs.audit!(user, deployment, description) + end + + @spec audit_deployment_deleted(User.t(), Deployment.t()) :: AuditLog.t() + def audit_deployment_deleted(user, deployment) do + description = "#{user.name} deleted deployment #{deployment.name}" + AuditLogs.audit!(user, deployment, description) + end + + @spec audit_deployment_toggle_active(User.t(), Deployment.t(), String.t()) :: AuditLog.t() + def audit_deployment_toggle_active(user, deployment, status) do + description = "#{user.name} marked deployment #{deployment.name} #{status}" + AuditLogs.audit!(user, deployment, description) + end + + @spec audit_deployment_mismatch(Device.t(), Deployment.t(), String.t()) :: AuditLog.t() + def audit_deployment_mismatch(device, deployment, reason) do + description = + "device no longer matches deployment #{deployment.name}'s requirements because of #{reason}" + + AuditLogs.audit!(device, deployment, description) + end + + @spec audit_deployment_change(Deployment.t(), String.t()) :: AuditLog.t() + def audit_deployment_change(deployment, change_string) do + description = "deployment #{deployment.name} #{change_string}" + AuditLogs.audit!(deployment, deployment, description) + end +end diff --git a/lib/nerves_hub/audit_logs/templates.ex b/lib/nerves_hub/audit_logs/templates/device_templates.ex similarity index 77% rename from lib/nerves_hub/audit_logs/templates.ex rename to lib/nerves_hub/audit_logs/templates/device_templates.ex index 5a140feed..7a2f4524c 100644 --- a/lib/nerves_hub/audit_logs/templates.ex +++ b/lib/nerves_hub/audit_logs/templates/device_templates.ex @@ -1,4 +1,8 @@ -defmodule NervesHub.AuditLogs.Templates do +defmodule NervesHub.AuditLogs.DeviceTemplates do + @moduledoc """ + Templates for and handling of audit logging for device operations. + """ + alias NervesHub.Firmwares.Firmware alias NervesHub.Accounts.User alias NervesHub.AuditLogs alias NervesHub.AuditLogs.AuditLog @@ -7,20 +11,21 @@ defmodule NervesHub.AuditLogs.Templates do require Logger - ### RESOURCE: DEVICE - ## General + @spec audit_reboot(User.t(), Device.t()) :: AuditLog.t() def audit_reboot(user, device) do description = "#{user.name} rebooted device #{device.identifier}" AuditLogs.audit!(user, device, description) end + @spec audit_request_action(User.t(), Device.t(), String.t()) :: AuditLog.t() def audit_request_action(user, device, action) do description = "#{user.name} requested the device (#{device.identifier}) #{action}" AuditLogs.audit!(user, device, description) end + @spec audit_unsupported_api_version(Device.t()) :: AuditLog.t() def audit_unsupported_api_version(device) do description = "device #{device.identifier} could not get extensions: Unsupported API version." @@ -50,11 +55,13 @@ defmodule NervesHub.AuditLogs.Templates do AuditLogs.audit_with_ref!(device, device, description, reference_id) end + @spec audit_update_attempt(Device.t()) :: AuditLog.t() def audit_update_attempt(device) do description = "device #{device.identifier} is attempting to update" AuditLogs.audit(device, device, description) end + @spec audit_pushed_available_update(User.t(), Device.t(), Deployment.t()) :: AuditLog.t() def audit_pushed_available_update(user, device, deployment) do description = "#{user.name} pushed available firmware update #{deployment.firmware.version} #{deployment.firmware.uuid} to device #{device.identifier}" @@ -62,6 +69,7 @@ defmodule NervesHub.AuditLogs.Templates do AuditLogs.audit!(user, device, description) end + @spec audit_firmware_pushed(User.t(), Device.t(), Firmware.t()) :: AuditLog.t() def audit_firmware_pushed(user, device, firmware) do description = "#{user.name} pushed firmware #{firmware.version} #{firmware.uuid} to device #{device.identifier}" @@ -69,11 +77,13 @@ defmodule NervesHub.AuditLogs.Templates do AuditLogs.audit!(user, device, description) end + @spec audit_firmware_metadata_updated(Device.t()) :: AuditLog.t() def audit_firmware_metadata_updated(device) do description = "device #{device.identifier} updated firmware metadata" AuditLogs.audit!(device, device, description) end + @spec audit_firmware_upgrade_blocked(Deployment.t(), Device.t()) :: AuditLog.t() def audit_firmware_upgrade_blocked(deployment, device) do description = """ Device #{device.identifier} automatically blocked firmware upgrades for #{deployment.penalty_timeout_minutes} minutes. @@ -83,6 +93,7 @@ defmodule NervesHub.AuditLogs.Templates do AuditLogs.audit!(deployment, device, description) end + @spec audit_firmware_updated(Device.t()) :: AuditLog.t() def audit_firmware_updated(device) do description = "device #{device.identifier} firmware set to version #{device.firmware_metadata.version} (#{device.firmware_metadata.uuid})" @@ -90,6 +101,7 @@ defmodule NervesHub.AuditLogs.Templates do AuditLogs.audit!(device, device, description) end + @spec audit_device_deployment_update_triggered(Device.t(), UUIDv7.t()) :: AuditLog.t() def audit_device_deployment_update_triggered(device, reference_id) do deployment = device.deployment firmware = deployment.firmware @@ -100,40 +112,6 @@ defmodule NervesHub.AuditLogs.Templates do AuditLogs.audit_with_ref!(deployment, device, description, reference_id) end - ### RESOUCE: DEPLOYMENT - - def audit_deployment_created(user, deployment) do - description = "#{user.name} created deployment #{deployment.name}" - AuditLogs.audit!(user, deployment, description) - end - - def audit_deployment_updated(user, deployment) do - description = "#{user.name} updated deployment #{deployment.name}" - AuditLogs.audit!(user, deployment, description) - end - - def audit_deployment_deleted(user, deployment) do - description = "#{user.name} deleted deployment #{deployment.name}" - AuditLogs.audit!(user, deployment, description) - end - - def audit_deployment_toggle_active(user, deployment, status) do - description = "#{user.name} marked deployment #{deployment.name} #{status}" - AuditLogs.audit!(user, deployment, description) - end - - def audit_deployment_mismatch(device, deployment, reason) do - description = - "device no longer matches deployment #{deployment.name}'s requirements because of #{reason}" - - AuditLogs.audit!(device, deployment, description) - end - - def audit_deployment_change(deployment, change_string) do - description = "deployment #{deployment.name} #{change_string}" - AuditLogs.audit!(deployment, deployment, description) - end - @spec audit_device_deployment_update(User.t(), Device.t(), Deployment.t()) :: AuditLog.t() def audit_device_deployment_update(user, device, deployment) do AuditLogs.audit!( @@ -153,6 +131,8 @@ defmodule NervesHub.AuditLogs.Templates do ) end + @spec audit_set_deployment(Device.t(), Deployment.t(), :one_found | :multiple_found) :: + AuditLog.t() def audit_set_deployment(device, deployment, :multiple_found) do AuditLogs.audit!( device, diff --git a/lib/nerves_hub/deployments.ex b/lib/nerves_hub/deployments.ex index 01ceb0741..b74eb73a6 100644 --- a/lib/nerves_hub/deployments.ex +++ b/lib/nerves_hub/deployments.ex @@ -3,7 +3,8 @@ defmodule NervesHub.Deployments do require Logger - alias NervesHub.AuditLogs.Templates + alias NervesHub.AuditLogs.DeploymentTemplates + alias NervesHub.AuditLogs.DeviceTemplates alias NervesHub.Deployments.Deployment alias NervesHub.Deployments.InflightDeploymentCheck alias NervesHub.Devices @@ -185,13 +186,13 @@ defmodule NervesHub.Deployments do payload = %{archive_id: archive_id} _ = broadcast(deployment, "archives/updated", payload) - Templates.audit_deployment_change(deployment, "has a new archive") + DeploymentTemplates.audit_deployment_change(deployment, "has a new archive") {:conditions, _new_conditions} -> - Templates.audit_deployment_change(deployment, "conditions changed") + DeploymentTemplates.audit_deployment_change(deployment, "conditions changed") {:is_active, is_active} when is_active != true -> - Templates.audit_deployment_change(deployment, "is inactive") + DeploymentTemplates.audit_deployment_change(deployment, "is inactive") _ -> :ignore @@ -334,7 +335,7 @@ defmodule NervesHub.Deployments do |> Ecto.Changeset.change(%{deployment_id: nil}) |> Repo.update!() - Templates.audit_deployment_mismatch(device, deployment, reason) + DeploymentTemplates.audit_deployment_mismatch(device, deployment, reason) else device end @@ -358,7 +359,7 @@ defmodule NervesHub.Deployments do [deployment] -> set_deployment_telemetry(:one_found, device, deployment) - Templates.audit_set_deployment(device, deployment, :one_found) + DeviceTemplates.audit_set_deployment(device, deployment, :one_found) device |> Devices.update_deployment(deployment) @@ -367,7 +368,7 @@ defmodule NervesHub.Deployments do [deployment | _] -> set_deployment_telemetry(:multiple_found, device, deployment) - Templates.audit_set_deployment(device, deployment, :multiple_found) + DeviceTemplates.audit_set_deployment(device, deployment, :multiple_found) device |> Devices.update_deployment(deployment) diff --git a/lib/nerves_hub/devices.ex b/lib/nerves_hub/devices.ex index bb3432386..be8bddf40 100644 --- a/lib/nerves_hub/devices.ex +++ b/lib/nerves_hub/devices.ex @@ -8,7 +8,7 @@ defmodule NervesHub.Devices do alias NervesHub.Accounts.OrgKey alias NervesHub.Accounts.User alias NervesHub.AuditLogs - alias NervesHub.AuditLogs.Templates + alias NervesHub.AuditLogs.DeviceTemplates alias NervesHub.Certificate alias NervesHub.Deployments.Deployment alias NervesHub.Deployments.Orchestrator @@ -682,7 +682,7 @@ defmodule NervesHub.Devices do end def update_firmware_metadata(device, metadata) do - Templates.audit_firmware_metadata_updated(device) + DeviceTemplates.audit_firmware_metadata_updated(device) update_device(device, %{firmware_metadata: metadata}) end @@ -840,7 +840,7 @@ defmodule NervesHub.Devices do |> DateTime.truncate(:second) |> DateTime.add(deployment.penalty_timeout_minutes * 60, :second) - Templates.audit_firmware_upgrade_blocked(deployment, device) + DeviceTemplates.audit_firmware_upgrade_blocked(deployment, device) clear_inflight_update(device) {:ok, device} = update_device(device, %{updates_blocked_until: blocked_until}) @@ -853,7 +853,7 @@ defmodule NervesHub.Devices do |> DateTime.truncate(:second) |> DateTime.add(deployment.penalty_timeout_minutes * 60, :second) - Templates.audit_firmware_upgrade_blocked(deployment, device) + DeviceTemplates.audit_firmware_upgrade_blocked(deployment, device) clear_inflight_update(device) {:ok, device} = update_device(device, %{updates_blocked_until: blocked_until}) @@ -876,7 +876,7 @@ defmodule NervesHub.Devices do Multi.new() |> Multi.update(:device, changeset) |> Multi.run(:audit_device, fn _, _ -> - Templates.audit_update_attempt(device) + DeviceTemplates.audit_update_attempt(device) end) |> Repo.transaction() |> case do @@ -894,7 +894,7 @@ defmodule NervesHub.Devices do firmware_uuid: device.firmware_metadata.uuid }) - Templates.audit_firmware_updated(device) + DeviceTemplates.audit_firmware_updated(device) # Clear the inflight update, no longer inflight! inflight_update = diff --git a/lib/nerves_hub_web/channels/device_channel.ex b/lib/nerves_hub_web/channels/device_channel.ex index 29ed69a45..93486ab3a 100644 --- a/lib/nerves_hub_web/channels/device_channel.ex +++ b/lib/nerves_hub_web/channels/device_channel.ex @@ -11,7 +11,7 @@ defmodule NervesHubWeb.DeviceChannel do require Logger alias NervesHub.Archives - alias NervesHub.AuditLogs.Templates + alias NervesHub.AuditLogs.DeviceTemplates alias NervesHub.Deployments alias NervesHub.Devices alias NervesHub.Devices.Device @@ -68,7 +68,7 @@ defmodule NervesHubWeb.DeviceChannel do # so check version before requesting extensions if safe_to_request_extensions?(socket.assigns.device_api_version), do: push(socket, "extensions:get", %{}), - else: Templates.audit_unsupported_api_version(device) + else: DeviceTemplates.audit_unsupported_api_version(device) {:noreply, socket} end @@ -138,7 +138,10 @@ defmodule NervesHubWeb.DeviceChannel do # If we get here, the device is connected and high probability it receives # the update message so we can Audit and later assert on this audit event # as a loosely valid attempt to update - Templates.audit_device_deployment_update_triggered(device, socket.assigns.reference_id) + DeviceTemplates.audit_device_deployment_update_triggered( + device, + socket.assigns.reference_id + ) Devices.update_started!(inflight_update) push(socket, "update", payload) diff --git a/lib/nerves_hub_web/controllers/api/deployment_controller.ex b/lib/nerves_hub_web/controllers/api/deployment_controller.ex index 3759b716f..2c0860459 100644 --- a/lib/nerves_hub_web/controllers/api/deployment_controller.ex +++ b/lib/nerves_hub_web/controllers/api/deployment_controller.ex @@ -1,7 +1,7 @@ defmodule NervesHubWeb.API.DeploymentController do use NervesHubWeb, :api_controller - alias NervesHub.AuditLogs.Templates + alias NervesHub.AuditLogs.DeploymentTemplates alias NervesHub.Deployments alias NervesHub.Deployments.Deployment alias NervesHub.Firmwares @@ -29,7 +29,7 @@ defmodule NervesHubWeb.API.DeploymentController do params <- Map.put(params, "org_id", org.id), params <- whitelist(params, @whitelist_fields), {:ok, deployment} <- Deployments.create_deployment(params) do - Templates.audit_deployment_created(user, deployment) + DeploymentTemplates.audit_deployment_created(user, deployment) conn |> put_status(:created) @@ -57,7 +57,7 @@ defmodule NervesHubWeb.API.DeploymentController do deployment_params <- whitelist(deployment_params, @whitelist_fields), {:ok, %Deployment{} = updated_deployment} <- Deployments.update_deployment(deployment, deployment_params) do - Templates.audit_deployment_updated(user, deployment) + DeploymentTemplates.audit_deployment_updated(user, deployment) render(conn, "show.json", deployment: updated_deployment) end diff --git a/lib/nerves_hub_web/controllers/api/device_controller.ex b/lib/nerves_hub_web/controllers/api/device_controller.ex index 42dfda127..01339bd76 100644 --- a/lib/nerves_hub_web/controllers/api/device_controller.ex +++ b/lib/nerves_hub_web/controllers/api/device_controller.ex @@ -2,7 +2,7 @@ defmodule NervesHubWeb.API.DeviceController do use NervesHubWeb, :api_controller alias NervesHub.Accounts - alias NervesHub.AuditLogs.Templates + alias NervesHub.AuditLogs.DeviceTemplates alias NervesHub.Devices alias NervesHub.Devices.DeviceCertificate alias NervesHub.Devices.UpdatePayload @@ -117,7 +117,7 @@ defmodule NervesHubWeb.API.DeviceController do case Devices.get_by_identifier(identifier) do {:ok, device} -> if Accounts.has_org_role?(device.org, user, :manage) do - Templates.audit_reboot(user, device) + DeviceTemplates.audit_reboot(user, device) _ = Endpoint.broadcast_from(self(), "device:#{device.id}", "reboot", %{}) @@ -204,7 +204,7 @@ defmodule NervesHubWeb.API.DeviceController do {:ok, device} = Devices.disable_updates(device, user) device = Repo.preload(device, [:device_certificates]) - Templates.audit_firmware_pushed(user, device, firmware) + DeviceTemplates.audit_firmware_pushed(user, device, firmware) payload = %UpdatePayload{ update_available: true, diff --git a/lib/nerves_hub_web/live/deployments/edit.ex b/lib/nerves_hub_web/live/deployments/edit.ex index a04cdb57f..e54664893 100644 --- a/lib/nerves_hub_web/live/deployments/edit.ex +++ b/lib/nerves_hub_web/live/deployments/edit.ex @@ -2,7 +2,7 @@ defmodule NervesHubWeb.Live.Deployments.Edit do use NervesHubWeb, :updated_live_view alias NervesHub.Archives - alias NervesHub.AuditLogs.Templates + alias NervesHub.AuditLogs.DeploymentTemplates alias NervesHub.Deployments alias NervesHub.Deployments.Deployment alias NervesHub.Firmwares @@ -46,7 +46,7 @@ defmodule NervesHubWeb.Live.Deployments.Edit do {:ok, updated} -> # Use original deployment so changes will get # marked in audit log - Templates.audit_deployment_updated(user, updated) + DeploymentTemplates.audit_deployment_updated(user, updated) socket |> put_flash(:info, "Deployment updated") diff --git a/lib/nerves_hub_web/live/deployments/new.ex b/lib/nerves_hub_web/live/deployments/new.ex index 0ae16c680..dd3ddf112 100644 --- a/lib/nerves_hub_web/live/deployments/new.ex +++ b/lib/nerves_hub_web/live/deployments/new.ex @@ -1,7 +1,7 @@ defmodule NervesHubWeb.Live.Deployments.New do use NervesHubWeb, :updated_live_view - alias NervesHub.AuditLogs.Templates + alias NervesHub.AuditLogs.DeploymentTemplates alias NervesHub.Deployments alias NervesHub.Deployments.Deployment alias NervesHub.Firmwares @@ -81,7 +81,7 @@ defmodule NervesHubWeb.Live.Deployments.New do |> noreply() {_, {:ok, deployment}} -> - Templates.audit_deployment_created(user, deployment) + DeploymentTemplates.audit_deployment_created(user, deployment) socket |> put_flash(:info, "Deployment created") diff --git a/lib/nerves_hub_web/live/deployments/show.ex b/lib/nerves_hub_web/live/deployments/show.ex index aa6f3e473..9e4e1fe5a 100644 --- a/lib/nerves_hub_web/live/deployments/show.ex +++ b/lib/nerves_hub_web/live/deployments/show.ex @@ -2,7 +2,7 @@ defmodule NervesHubWeb.Live.Deployments.Show do use NervesHubWeb, :updated_live_view alias NervesHub.AuditLogs - alias NervesHub.AuditLogs.Templates + alias NervesHub.AuditLogs.DeploymentTemplates alias NervesHub.Deployments alias NervesHub.Deployments.Deployment alias NervesHub.Devices @@ -65,7 +65,7 @@ defmodule NervesHubWeb.Live.Deployments.Show do {:ok, deployment} = Deployments.update_deployment(deployment, %{is_active: value}) active_str = if value, do: "active", else: "inactive" - Templates.audit_deployment_toggle_active(user, deployment, active_str) + DeploymentTemplates.audit_deployment_toggle_active(user, deployment, active_str) socket |> put_flash(:info, "Deployment set #{active_str}") @@ -80,7 +80,7 @@ defmodule NervesHubWeb.Live.Deployments.Show do {:ok, _} = Deployments.delete_deployment(deployment) - Templates.audit_deployment_deleted(user, deployment) + DeploymentTemplates.audit_deployment_deleted(user, deployment) socket |> put_flash(:info, "Deployment successfully deleted") diff --git a/lib/nerves_hub_web/live/devices/index.ex b/lib/nerves_hub_web/live/devices/index.ex index 48ac7daa3..3d54ec9d6 100644 --- a/lib/nerves_hub_web/live/devices/index.ex +++ b/lib/nerves_hub_web/live/devices/index.ex @@ -5,7 +5,7 @@ defmodule NervesHubWeb.Live.Devices.Index do require OpenTelemetry.Tracer, as: Tracer - alias NervesHub.AuditLogs.Templates + alias NervesHub.AuditLogs.DeviceTemplates alias NervesHub.Devices alias NervesHub.Devices.Alarms alias NervesHub.Devices.Metrics @@ -373,7 +373,7 @@ defmodule NervesHubWeb.Live.Devices.Index do {:ok, device} = Devices.get_device_by_identifier(org, device_identifier) - Templates.audit_reboot(user, device) + DeviceTemplates.audit_reboot(user, device) socket.endpoint.broadcast_from(self(), "device:#{device.id}", "reboot", %{}) diff --git a/lib/nerves_hub_web/live/devices/show.ex b/lib/nerves_hub_web/live/devices/show.ex index 47cc490da..2b639e655 100644 --- a/lib/nerves_hub_web/live/devices/show.ex +++ b/lib/nerves_hub_web/live/devices/show.ex @@ -4,7 +4,7 @@ defmodule NervesHubWeb.Live.Devices.Show do require Logger alias NervesHub.AuditLogs - alias NervesHub.AuditLogs.Templates + alias NervesHub.AuditLogs.DeviceTemplates alias NervesHub.Deployments alias NervesHub.Devices alias NervesHub.Devices.Alarms @@ -191,7 +191,7 @@ defmodule NervesHubWeb.Live.Devices.Show do authorized!(:"device:reboot", org_user) - Templates.audit_reboot(user, device) + DeviceTemplates.audit_reboot(user, device) socket.endpoint.broadcast_from(self(), "device:#{device.id}", "reboot", %{}) @@ -203,7 +203,7 @@ defmodule NervesHubWeb.Live.Devices.Show do authorized!(:"device:reconnect", org_user) - Templates.audit_request_action(user, device, "reconnect") + DeviceTemplates.audit_request_action(user, device, "reconnect") socket.endpoint.broadcast("device_socket:#{device.id}", "disconnect", %{}) @@ -215,7 +215,7 @@ defmodule NervesHubWeb.Live.Devices.Show do authorized!(:"device:identify", org_user) - Templates.audit_request_action(user, device, "identify itself") + DeviceTemplates.audit_request_action(user, device, "identify itself") socket.endpoint.broadcast_from(self(), "device:#{socket.assigns.device.id}", "identify", %{}) @@ -311,7 +311,7 @@ defmodule NervesHubWeb.Live.Devices.Show do ) do deployment = Enum.find(eligible_deployments, &(&1.id == String.to_integer(deployment_id))) device = Devices.update_deployment(device, deployment) - _ = Templates.audit_device_deployment_update(user, device, deployment) + _ = DeviceTemplates.audit_device_deployment_update(user, device, deployment) socket |> assign(:device, device) @@ -330,7 +330,7 @@ defmodule NervesHubWeb.Live.Devices.Show do {:ok, meta} = Firmwares.metadata_from_firmware(firmware) {:ok, device} = Devices.disable_updates(device, user) - Templates.audit_firmware_pushed(user, device, firmware) + DeviceTemplates.audit_firmware_pushed(user, device, firmware) payload = %UpdatePayload{ update_available: true, @@ -355,7 +355,7 @@ defmodule NervesHubWeb.Live.Devices.Show do case Devices.told_to_update(device, deployment) do {:ok, inflight_update} -> - Templates.audit_pushed_available_update(user, device, deployment) + DeviceTemplates.audit_pushed_available_update(user, device, deployment) _ = NervesHubWeb.Endpoint.broadcast( From 426259dd4e2b7424e60493e8176c1c51507f3c14 Mon Sep 17 00:00:00 2001 From: Elin Olsson Date: Tue, 14 Jan 2025 10:30:40 +0100 Subject: [PATCH 5/8] Remove unused audit log templates --- .../audit_logs/templates/device_templates.ex | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/lib/nerves_hub/audit_logs/templates/device_templates.ex b/lib/nerves_hub/audit_logs/templates/device_templates.ex index 7a2f4524c..acf186305 100644 --- a/lib/nerves_hub/audit_logs/templates/device_templates.ex +++ b/lib/nerves_hub/audit_logs/templates/device_templates.ex @@ -35,25 +35,6 @@ defmodule NervesHub.AuditLogs.DeviceTemplates do end ## Firmware and upgrades - # Deprecated? - def audit_device_assigned(device, reference_id) do - description = - "device #{device.identifier} reloaded deployment and is attached to deployment #{device.deployment.name}" - - AuditLogs.audit_with_ref!(device, device, description, reference_id) - end - - # Deprecated? - def audit_resolve_changed_deployment(device, reference_id) do - description = - if device.deployment_id do - "device #{device.identifier} reloaded deployment and is attached to deployment #{device.deployment.name}" - else - "device #{device.identifier} reloaded deployment and is no longer attached to a deployment" - end - - AuditLogs.audit_with_ref!(device, device, description, reference_id) - end @spec audit_update_attempt(Device.t()) :: AuditLog.t() def audit_update_attempt(device) do From 64d79be684f66f0447b59005bb3e59f3520e3aab Mon Sep 17 00:00:00 2001 From: Elin Olsson Date: Tue, 21 Jan 2025 13:35:44 +0100 Subject: [PATCH 6/8] Use DeviceTemplates in details component --- .../components/device_page/details.ex | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/lib/nerves_hub_web/components/device_page/details.ex b/lib/nerves_hub_web/components/device_page/details.ex index c6352dd3e..314a37f3e 100644 --- a/lib/nerves_hub_web/components/device_page/details.ex +++ b/lib/nerves_hub_web/components/device_page/details.ex @@ -3,8 +3,7 @@ defmodule NervesHubWeb.Components.DevicePage.Details do require Logger - alias NervesHub.AuditLogs - alias NervesHub.AuditLogs.Templates + alias NervesHub.AuditLogs.DeviceTemplates alias NervesHub.Deployments alias NervesHub.Devices alias NervesHub.Devices.Alarms @@ -437,7 +436,7 @@ defmodule NervesHubWeb.Components.DevicePage.Details do deployment = Enum.find(eligible_deployments, &(&1.id == String.to_integer(deployment_id))) device = Devices.update_deployment(device, deployment) - _ = Templates.audit_device_deployment_update(user, device, deployment) + _ = DeviceTemplates.audit_device_deployment_update(user, device, deployment) send(self(), :reload_device) @@ -454,10 +453,7 @@ defmodule NervesHubWeb.Components.DevicePage.Details do deployment = NervesHub.Repo.preload(deployment, :firmware) - description = - "#{user.name} pushed available firmware update #{deployment.firmware.version} #{deployment.firmware.uuid} to device #{device.identifier}" - - AuditLogs.audit!(user, device, description) + DeviceTemplates.audit_pushed_available_update(user, device, deployment) case Devices.told_to_update(device, deployment) do {:ok, inflight_update} -> @@ -496,10 +492,7 @@ defmodule NervesHubWeb.Components.DevicePage.Details do {:ok, meta} = Firmwares.metadata_from_firmware(firmware) {:ok, device} = Devices.disable_updates(device, user) - description = - "User #{user.name} pushed firmware #{firmware.version} #{firmware.uuid} to device #{device.identifier}" - - AuditLogs.audit!(user, device, description) + DeviceTemplates.audit_firmware_pushed(user, device, firmware) payload = %UpdatePayload{ update_available: true, From 0ee47372089fdac88262ddc7747c98c51e75a8da Mon Sep 17 00:00:00 2001 From: Elin Olsson Date: Wed, 22 Jan 2025 09:23:33 +0100 Subject: [PATCH 7/8] standardize formatting for log descriptions --- .../templates/deployment_templates.ex | 12 +++++------ .../audit_logs/templates/device_templates.ex | 20 +++++++++---------- lib/nerves_hub/devices.ex | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/nerves_hub/audit_logs/templates/deployment_templates.ex b/lib/nerves_hub/audit_logs/templates/deployment_templates.ex index 84bd8df12..0c6ef90d6 100644 --- a/lib/nerves_hub/audit_logs/templates/deployment_templates.ex +++ b/lib/nerves_hub/audit_logs/templates/deployment_templates.ex @@ -9,39 +9,39 @@ defmodule NervesHub.AuditLogs.DeploymentTemplates do @spec audit_deployment_created(User.t(), Deployment.t()) :: AuditLog.t() def audit_deployment_created(user, deployment) do - description = "#{user.name} created deployment #{deployment.name}" + description = "User #{user.name} created deployment #{deployment.name}" AuditLogs.audit!(user, deployment, description) end @spec audit_deployment_updated(User.t(), Deployment.t()) :: AuditLog.t() def audit_deployment_updated(user, deployment) do - description = "#{user.name} updated deployment #{deployment.name}" + description = "User #{user.name} updated deployment #{deployment.name}" AuditLogs.audit!(user, deployment, description) end @spec audit_deployment_deleted(User.t(), Deployment.t()) :: AuditLog.t() def audit_deployment_deleted(user, deployment) do - description = "#{user.name} deleted deployment #{deployment.name}" + description = "User #{user.name} deleted deployment #{deployment.name}" AuditLogs.audit!(user, deployment, description) end @spec audit_deployment_toggle_active(User.t(), Deployment.t(), String.t()) :: AuditLog.t() def audit_deployment_toggle_active(user, deployment, status) do - description = "#{user.name} marked deployment #{deployment.name} #{status}" + description = "User #{user.name} marked deployment #{deployment.name} #{status}" AuditLogs.audit!(user, deployment, description) end @spec audit_deployment_mismatch(Device.t(), Deployment.t(), String.t()) :: AuditLog.t() def audit_deployment_mismatch(device, deployment, reason) do description = - "device no longer matches deployment #{deployment.name}'s requirements because of #{reason}" + "Device no longer matches deployment #{deployment.name}'s requirements because of #{reason}" AuditLogs.audit!(device, deployment, description) end @spec audit_deployment_change(Deployment.t(), String.t()) :: AuditLog.t() def audit_deployment_change(deployment, change_string) do - description = "deployment #{deployment.name} #{change_string}" + description = "Deployment #{deployment.name} #{change_string}" AuditLogs.audit!(deployment, deployment, description) end end diff --git a/lib/nerves_hub/audit_logs/templates/device_templates.ex b/lib/nerves_hub/audit_logs/templates/device_templates.ex index acf186305..e9ad99ab9 100644 --- a/lib/nerves_hub/audit_logs/templates/device_templates.ex +++ b/lib/nerves_hub/audit_logs/templates/device_templates.ex @@ -15,20 +15,20 @@ defmodule NervesHub.AuditLogs.DeviceTemplates do @spec audit_reboot(User.t(), Device.t()) :: AuditLog.t() def audit_reboot(user, device) do - description = "#{user.name} rebooted device #{device.identifier}" + description = "User #{user.name} rebooted device #{device.identifier}" AuditLogs.audit!(user, device, description) end @spec audit_request_action(User.t(), Device.t(), String.t()) :: AuditLog.t() def audit_request_action(user, device, action) do - description = "#{user.name} requested the device (#{device.identifier}) #{action}" + description = "User #{user.name} requested the device (#{device.identifier}) #{action}" AuditLogs.audit!(user, device, description) end @spec audit_unsupported_api_version(Device.t()) :: AuditLog.t() def audit_unsupported_api_version(device) do description = - "device #{device.identifier} could not get extensions: Unsupported API version." + "Device #{device.identifier} could not get extensions: Unsupported API version." AuditLogs.audit!(device, device, description) Logger.info("[DeviceChannel] #{description}") @@ -38,14 +38,14 @@ defmodule NervesHub.AuditLogs.DeviceTemplates do @spec audit_update_attempt(Device.t()) :: AuditLog.t() def audit_update_attempt(device) do - description = "device #{device.identifier} is attempting to update" + description = "Device #{device.identifier} is attempting to update" AuditLogs.audit(device, device, description) end @spec audit_pushed_available_update(User.t(), Device.t(), Deployment.t()) :: AuditLog.t() def audit_pushed_available_update(user, device, deployment) do description = - "#{user.name} pushed available firmware update #{deployment.firmware.version} #{deployment.firmware.uuid} to device #{device.identifier}" + "User #{user.name} pushed available firmware update #{deployment.firmware.version} #{deployment.firmware.uuid} to device #{device.identifier}" AuditLogs.audit!(user, device, description) end @@ -53,14 +53,14 @@ defmodule NervesHub.AuditLogs.DeviceTemplates do @spec audit_firmware_pushed(User.t(), Device.t(), Firmware.t()) :: AuditLog.t() def audit_firmware_pushed(user, device, firmware) do description = - "#{user.name} pushed firmware #{firmware.version} #{firmware.uuid} to device #{device.identifier}" + "User #{user.name} pushed firmware #{firmware.version} #{firmware.uuid} to device #{device.identifier}" AuditLogs.audit!(user, device, description) end @spec audit_firmware_metadata_updated(Device.t()) :: AuditLog.t() def audit_firmware_metadata_updated(device) do - description = "device #{device.identifier} updated firmware metadata" + description = "Device #{device.identifier} updated firmware metadata" AuditLogs.audit!(device, device, description) end @@ -77,7 +77,7 @@ defmodule NervesHub.AuditLogs.DeviceTemplates do @spec audit_firmware_updated(Device.t()) :: AuditLog.t() def audit_firmware_updated(device) do description = - "device #{device.identifier} firmware set to version #{device.firmware_metadata.version} (#{device.firmware_metadata.uuid})" + "Device #{device.identifier} firmware set to version #{device.firmware_metadata.version} (#{device.firmware_metadata.uuid})" AuditLogs.audit!(device, device, description) end @@ -88,7 +88,7 @@ defmodule NervesHub.AuditLogs.DeviceTemplates do firmware = deployment.firmware description = - "deployment #{deployment.name} update triggered device #{device.identifier} to update firmware #{firmware.uuid}" + "Deployment #{deployment.name} update triggered device #{device.identifier} to update firmware #{firmware.uuid}" AuditLogs.audit_with_ref!(deployment, device, description, reference_id) end @@ -98,7 +98,7 @@ defmodule NervesHub.AuditLogs.DeviceTemplates do AuditLogs.audit!( user, device, - "#{user.name} set #{device.identifier}'s deployment to #{deployment.name}" + "User #{user.name} set #{device.identifier}'s deployment to #{deployment.name}" ) end diff --git a/lib/nerves_hub/devices.ex b/lib/nerves_hub/devices.ex index be8bddf40..ef77ff26d 100644 --- a/lib/nerves_hub/devices.ex +++ b/lib/nerves_hub/devices.ex @@ -950,7 +950,7 @@ defmodule NervesHub.Devices do _ = maybe_copy_firmware_keys(device, product.org) description = - "user #{user.name} moved device #{device.identifier} to #{product.org.name} : #{product.name}" + "User #{user.name} moved device #{device.identifier} to #{product.org.name} : #{product.name}" source_product = %Product{ id: device.product_id, @@ -1035,7 +1035,7 @@ defmodule NervesHub.Devices do end def clear_penalty_box(%Device{} = device, user) do - description = "user #{user.name} removed device #{device.identifier} from the penalty box" + description = "User #{user.name} removed device #{device.identifier} from the penalty box" params = %{updates_blocked_until: nil, update_attempts: []} update_device_with_audit(device, params, user, description) end From 5c6f9453fc0362acbf8a3e4b3a805b6e7f9d10ed Mon Sep 17 00:00:00 2001 From: Elin Olsson Date: Wed, 22 Jan 2025 09:34:48 +0100 Subject: [PATCH 8/8] fix broken test --- test/nerves_hub_web/channels/websocket_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/nerves_hub_web/channels/websocket_test.exs b/test/nerves_hub_web/channels/websocket_test.exs index 70fac4342..8170137b9 100644 --- a/test/nerves_hub_web/channels/websocket_test.exs +++ b/test/nerves_hub_web/channels/websocket_test.exs @@ -797,7 +797,7 @@ defmodule NervesHubWeb.WebsocketTest do [log, _, _] = AuditLogs.logs_by(device) assert log.description == - "device no longer matches deployment Every Device's requirements because of mismatched architecture and platform" + "Device no longer matches deployment Every Device's requirements because of mismatched architecture and platform" SocketClient.clean_close(socket) end