fix(portal): Redact entire connection_opts param (#8946)

The LoggerJSON Redactor only redacts top-level keys, so we need to
redact the entire `connection_opts` param to redact its contained
password.

We also don't need to pass around `connection_opts` across the entire
ReplicationConnection process state, only for the initial connection, so
we refactor that out of the `state`.
This commit is contained in:
Jamil
2025-04-30 09:33:21 -07:00
committed by GitHub
parent ab617bf2d0
commit a98a9867af
4 changed files with 28 additions and 16 deletions

View File

@@ -23,11 +23,7 @@ defmodule Domain.Application do
Domain.PubSub,
# WAL replication
%{
id: Domain.Events.ReplicationConnection,
start: {Domain.Events.ReplicationConnection, :start_link, [replication_instance()]},
restart: :transient
},
replication_child_spec(),
# Infrastructure services
# Note: only one of platform adapters will be actually started.
@@ -52,9 +48,21 @@ defmodule Domain.Application do
]
end
defp replication_instance do
config = Application.fetch_env!(:domain, Domain.Events.ReplicationConnection)
struct(Domain.Events.ReplicationConnection, config)
defp replication_child_spec do
{connection_opts, config} =
Application.fetch_env!(:domain, Domain.Events.ReplicationConnection)
|> Keyword.pop(:connection_opts)
init_state = %{
connection_opts: connection_opts,
instance: struct(Domain.Events.ReplicationConnection, config)
}
%{
id: Domain.Events.ReplicationConnection,
start: {Domain.Events.ReplicationConnection, :start_link, [init_state]},
restart: :transient
}
end
defp configure_logger do

View File

@@ -28,7 +28,6 @@ defmodule Domain.Events.ReplicationConnection do
@type t :: %__MODULE__{
schema: String.t(),
connection_opts: Keyword.t(),
step:
:disconnected
| :check_publication
@@ -45,7 +44,6 @@ defmodule Domain.Events.ReplicationConnection do
relations: map()
}
defstruct schema: "public",
connection_opts: [],
step: :disconnected,
publication_name: "events",
replication_slot_name: "events_slot",
@@ -54,9 +52,9 @@ defmodule Domain.Events.ReplicationConnection do
table_subscriptions: [],
relations: %{}
def start_link(%__MODULE__{} = instance) do
def start_link(%{instance: %__MODULE__{} = instance, connection_opts: connection_opts}) do
# Start only one ReplicationConnection in the cluster.
opts = instance.connection_opts ++ [name: {:global, __MODULE__}]
opts = connection_opts ++ [name: {:global, __MODULE__}]
case(Postgrex.ReplicationConnection.start_link(__MODULE__, instance, opts)) do
{:ok, pid} ->

View File

@@ -7,7 +7,6 @@ defmodule Domain.Events.ReplicationConnectionTest do
# Used to test callbacks, not used for live connection
@mock_state %ReplicationConnection{
schema: "test_schema",
connection_opts: [],
step: :disconnected,
publication_name: "test_pub",
replication_slot_name: "test_slot",
@@ -19,14 +18,20 @@ defmodule Domain.Events.ReplicationConnectionTest do
# Used to test live connection
setup_all do
config =
{config, connection_opts} =
Application.fetch_env!(:domain, Domain.Events.ReplicationConnection)
|> Keyword.pop(:connection_opts)
instance = struct(Domain.Events.ReplicationConnection, config)
init_state = %{
connection_opts: connection_opts,
instance: instance
}
child_spec = %{
id: Domain.Events.ReplicationConnection,
start: {Domain.Events.ReplicationConnection, :start_link, [instance]},
start: {Domain.Events.ReplicationConnection, :start_link, [init_state]},
restart: :transient
}

View File

@@ -49,7 +49,8 @@ secret_keys = [
"private_key",
"preshared_key",
"session",
"sessions"
"sessions",
"connection_opts"
]
config :phoenix, :filter_parameters, secret_keys