feat: add audit logging to grant_sudo_mode/1

This commit is contained in:
Graham McIntire 2026-02-01 14:09:40 -06:00
parent ada851e7ed
commit 92350173b0
No known key found for this signature in database
3 changed files with 42 additions and 4 deletions

View file

@ -15,6 +15,7 @@ defmodule Towerops.Accounts do
alias Towerops.Accounts.UserRecoveryCode
alias Towerops.Accounts.UserToken
alias Towerops.Accounts.UserTotpDevice
alias Towerops.Admin.AuditLogger
alias Towerops.GeoIP
alias Towerops.Repo
@ -633,9 +634,19 @@ defmodule Towerops.Accounts do
def grant_sudo_mode(%User{} = user) do
now = DateTime.utc_now()
user
|> User.sudo_changeset(%{last_sudo_at: now})
|> Repo.update()
with {:ok, _updated_user} = result <-
user
|> User.sudo_changeset(%{last_sudo_at: now})
|> Repo.update() do
# Log sudo mode grant for security auditing
AuditLogger.log_event("sudo_mode_granted", nil,
actor_id: user.id,
target_user_id: user.id,
metadata: %{granted_at: now}
)
result
end
end
@doc """

View file

@ -61,7 +61,8 @@ defmodule Towerops.Admin.AuditLog do
"monitoring_data_queried",
# Security events
"failed_access_attempt",
"privilege_escalation"
"privilege_escalation",
"sudo_mode_granted"
])
end
end

View file

@ -5,6 +5,7 @@ defmodule Towerops.Accounts.GrantSudoModeTest do
alias Towerops.Accounts
alias Towerops.Accounts.User
alias Towerops.Admin
describe "grant_sudo_mode/1" do
test "updates user's last_sudo_at timestamp" do
@ -40,5 +41,30 @@ defmodule Towerops.Accounts.GrantSudoModeTest do
refute changeset.valid?
assert "can't be blank" in errors_on(changeset).last_sudo_at
end
test "creates audit log entry when sudo mode is granted" do
user = user_fixture()
# Verify no audit logs exist before
logs_before = Admin.list_audit_logs_for_user(user.id)
assert Enum.empty?(logs_before)
# Grant sudo mode
{:ok, updated_user} = Accounts.grant_sudo_mode(user)
# Verify audit log was created
logs_after = Admin.list_audit_logs_for_user(user.id)
assert length(logs_after) == 1
[log] = logs_after
assert log.action == "sudo_mode_granted"
assert log.superuser_id == user.id
assert log.target_user_id == user.id
assert log.metadata["granted_at"]
# Verify the granted_at timestamp matches the user's last_sudo_at
granted_at = log.metadata["granted_at"] |> DateTime.from_iso8601() |> elem(1)
assert DateTime.diff(granted_at, updated_user.last_sudo_at, :second) == 0
end
end
end