Complete nested module alias fixes and update Sobelow skips

Software design fixes:
- Add proper aliases for all nested modules
- release.ex: Ecto.Adapters.SQL
- packet_consumer.ex: Aprsme.Cluster.PacketDistributor
- cleanup_scheduler.ex: Aprsme.Workers.PacketCleanupWorker
- health_check.ex: Ecto.Adapters.SQL
- status_live/index.ex: Aprsme.Cluster.LeaderElection
- packet_receiver.ex: Aprsme.Cluster.LeaderElection
- packet_distributor.ex: Aprsme.Cluster.LeaderElection, AprsmeWeb.MapLive.PacketStore

Security:
- Update .sobelow-skips for false positive SQL injection warning (div is builtin function)

All 13 software design suggestions now complete.
All 13 warnings previously fixed.
Remaining: 42 refactoring opportunities (complex/nested functions)
This commit is contained in:
Graham McIntire 2026-02-09 11:26:47 -06:00
parent dc0bc7bbdf
commit d8606bb609
No known key found for this signature in database
8 changed files with 25 additions and 9 deletions

View file

@ -14,4 +14,5 @@ SQL.Query: SQL injection,lib/aprsme/release.ex:159,5D9BE66
SQL.Query: SQL injection,lib/aprsme/db_optimizer.ex:107,5ECC490
SQL.Query: SQL injection,lib/aprsme_web/live/info_live/show.ex:576,6A503E9
XSS.Raw: XSS,lib/aprsme_web/components/core_components.ex:52,6B2C0EC
SQL.Query: SQL injection,lib/aprsme/db_optimizer.ex:129,711E151
SQL.Query: SQL injection,lib/aprsme/db_optimizer.ex:129,711E151
SQL.Query: SQL injection,lib/aprsme/release.ex:163,7079EA4

View file

@ -8,6 +8,8 @@ defmodule Aprsme.CleanupScheduler do
use GenServer
alias Aprsme.Workers.PacketCleanupWorker
require Logger
def start_link(opts) do
@ -38,7 +40,7 @@ defmodule Aprsme.CleanupScheduler do
# Run cleanup directly in a supervised task
Task.start(fn ->
try do
Aprsme.Workers.PacketCleanupWorker.perform(%{})
PacketCleanupWorker.perform(%{})
rescue
error ->
Logger.error("Packet cleanup task failed: #{inspect(error)}")

View file

@ -4,6 +4,9 @@ defmodule Aprsme.Cluster.PacketDistributor do
This ensures all nodes can serve real-time updates via LiveView while
only the leader maintains the APRS-IS connection.
"""
alias Aprsme.Cluster.LeaderElection
alias AprsmeWeb.MapLive.PacketStore
require Logger
@pubsub_topic "cluster:packets"
@ -12,7 +15,7 @@ defmodule Aprsme.Cluster.PacketDistributor do
# Only distribute if clustering is enabled and we're the leader
cluster_enabled = Application.get_env(:aprsme, :cluster_enabled, false)
if cluster_enabled and Aprsme.Cluster.LeaderElection.leader?() do
if cluster_enabled and LeaderElection.leader?() do
# Broadcast to all nodes including self
Phoenix.PubSub.broadcast(
Aprsme.PubSub,
@ -33,7 +36,7 @@ defmodule Aprsme.Cluster.PacketDistributor do
Aprsme.StreamingPacketsPubSub.broadcast_packet(packet)
# Update packet store for LiveView
AprsmeWeb.MapLive.PacketStore.store_packet(packet)
PacketStore.store_packet(packet)
Logger.debug("Received distributed packet on node #{node()}")
end

View file

@ -6,6 +6,7 @@ defmodule Aprsme.Cluster.PacketReceiver do
"""
use GenServer
alias Aprsme.Cluster.LeaderElection
alias Aprsme.Cluster.PacketDistributor
require Logger
@ -27,7 +28,7 @@ defmodule Aprsme.Cluster.PacketReceiver do
@impl true
def handle_info({:distributed_packet, packet}, state) do
# Only process if we're not the leader (leader already processed locally)
if !Aprsme.Cluster.LeaderElection.leader?() do
if !LeaderElection.leader?() do
PacketDistributor.handle_distributed_packet({:distributed_packet, packet})
end

View file

@ -6,6 +6,7 @@ defmodule Aprsme.PacketConsumer do
use GenStage
alias Aprs.Types.ParseError
alias Aprsme.Cluster.PacketDistributor
alias Aprsme.LogSanitizer
alias Aprsme.Repo
@ -346,7 +347,7 @@ defmodule Aprsme.PacketConsumer do
if cluster_enabled do
# Use cluster distributor to broadcast to all nodes
Aprsme.Cluster.PacketDistributor.distribute_packet(packet)
PacketDistributor.distribute_packet(packet)
else
# Normal single-node broadcasting
Aprsme.StreamingPacketsPubSub.broadcast_packet(packet)

View file

@ -3,6 +3,8 @@ defmodule Aprsme.Release do
Used for executing DB release tasks when run in production without Mix
installed.
"""
alias Ecto.Adapters.SQL
@app :aprsme
def migrate do
@ -156,7 +158,9 @@ defmodule Aprsme.Release do
Aprsme.Repo,
fn repo ->
# Set session-level timeout for this connection
Ecto.Adapters.SQL.query!(repo, "SET statement_timeout = '#{div(timeout, 1000)}s'")
# credo:disable-for-next-line
# sobelow_skip ["SQL.Query"]
SQL.query!(repo, "SET statement_timeout = '#{div(timeout, 1000)}s'")
Ecto.Migrator.run(repo, :up, all: true)
end,
timeout: timeout

View file

@ -4,6 +4,8 @@ defmodule AprsmeWeb.StatusLive.Index do
"""
use AprsmeWeb, :live_view
alias Aprsme.Cluster.LeaderElection
require Logger
# 5 seconds - reduced from 1 second to improve performance
@ -383,7 +385,7 @@ defmodule AprsmeWeb.StatusLive.Index do
# Private functions
defp get_aprs_status do
Aprsme.Cluster.LeaderElection.get_cluster_aprs_status()
LeaderElection.get_cluster_aprs_status()
rescue
error ->
require Logger

View file

@ -6,6 +6,8 @@ defmodule AprsmeWeb.Plugs.HealthCheck do
import Plug.Conn
alias Ecto.Adapters.SQL
require Logger
def init(opts), do: opts
@ -75,7 +77,7 @@ defmodule AprsmeWeb.Plugs.HealthCheck do
end
defp check_database_connection do
case Ecto.Adapters.SQL.query(Aprsme.Repo, "SELECT 1", [], timeout: 1000) do
case SQL.query(Aprsme.Repo, "SELECT 1", [], timeout: 1000) do
{:ok, _} -> :ok
_ -> {:error, "Database connection failed"}
end