Add multi-database discovery and grouping features
Some checks are pending
PostgreSQL Compatibility Matrix / PG14 smoke (push) Waiting to run
PostgreSQL Compatibility Matrix / PG15 smoke (push) Successful in 28s
PostgreSQL Compatibility Matrix / PG16 smoke (push) Successful in 7s
PostgreSQL Compatibility Matrix / PG17 smoke (push) Successful in 7s
PostgreSQL Compatibility Matrix / PG18 smoke (push) Successful in 6s

This update introduces optional automatic discovery and onboarding of all databases on a PostgreSQL instance. It also enhances the frontend UI with grouped target display and navigation, making it easier to view and manage related databases. Additionally, new backend endpoints and logic ensure seamless integration of these features.
This commit is contained in:
2026-02-12 16:54:22 +01:00
parent 1b12c01366
commit fa8958934f
7 changed files with 307 additions and 28 deletions

View File

@@ -7,11 +7,12 @@ const emptyForm = {
name: "",
host: "",
port: 5432,
dbname: "",
dbname: "postgres",
username: "",
password: "",
sslmode: "prefer",
use_pg_stat_statements: true,
discover_all_databases: false,
owner_user_ids: [],
tags: {},
};
@@ -276,8 +277,18 @@ export function TargetsPage() {
<input placeholder="5432" value={form.port} onChange={(e) => setForm({ ...form, port: Number(e.target.value) })} type="number" required />
</div>
<div className="field">
<label>DB Name</label>
<input placeholder="e.g. postgres or appdb" value={form.dbname} onChange={(e) => setForm({ ...form, dbname: e.target.value })} required />
<label>{form.discover_all_databases ? "Discovery DB" : "DB Name"}</label>
<input
placeholder={form.discover_all_databases ? "e.g. postgres" : "e.g. postgres or appdb"}
value={form.dbname}
onChange={(e) => setForm({ ...form, dbname: e.target.value })}
required
/>
<small>
{form.discover_all_databases
? "Connection database used to crawl all available databases on this instance."
: "Single database to monitor for this target."}
</small>
</div>
<div className="field">
<label>Username</label>
@@ -313,6 +324,21 @@ export function TargetsPage() {
</span>
</label>
</div>
<div className="field toggle-field">
<label>Scope</label>
<label className="toggle-check">
<input
type="checkbox"
checked={!!form.discover_all_databases}
onChange={(e) => setForm({ ...form, discover_all_databases: e.target.checked })}
/>
<span className="toggle-ui" aria-hidden="true" />
<span className="toggle-copy">
<strong>Discover and add all databases</strong>
<small>Requires credentials with access to list databases (typically a superuser).</small>
</span>
</label>
</div>
<div className="field field-full">
<label>Responsible Users (Target Owners)</label>
<OwnerPicker