amjadiqbal/laravel-sql-dashboard
A Laravel package that adds a SQL dashboard to your application, letting you run queries and inspect database results through a simple web interface. Useful for quick data checks, debugging, and lightweight SQL monitoring.
What this package is (as evidenced by v0.1.1): a Laravel package that lets users author and save SQL from a web dashboard, run it against configured connections, share queries/dashboards, and attach scheduled "checks" that raise alerts (mail; Slack described as untested) when a result crosses a threshold (alerts.rows_in_alert). Access is controlled by Laravel gates — a general "use" gate defaulting to app()->environment('local'), and an "edit" gate.
Architecture fit
U&"..." escapes, then matches against function families (server-file, large-object, replication, backend-signal, logical decoding, dblink, postgres_fdw, MySQL wait/lock and UDF names). The README now states plainly this is a tokenizer, not a full SQL parser — treat the SQL gate as defence-in-depth, not a trust boundary.pg_read_server_files/pg_write_server_files/pg_execute_server_program/pg_signal_backend, able to execute dblink or server-file functions, or holding USAGE on a foreign server are refused; MySQL users with PROCESS, FILE or SUPER are refused. This is the more durable control: it survives SQL-gate bypasses by shrinking the blast radius to what the role can do.GET_LOCK locks are released after each query because they outlive the rolled-back transaction. This is a meaningful architectural detail — it implies queries run inside a transaction that is rolled back, and that the package is aware of session-scoped state. It also implies persistent/reused connections are a consideration.Integration feasibility
composer require, publish config and migrations, wire the gates, point at a connection. No external services required for the core loop; Slack/mail are optional.schedule:run will silently never alert.alerts.rows_in_alert was only just documented), so expect to re-read published config on each bump.Technical risk
PREPARE/EXECUTE, DO blocks, CTEs, stored procedures, COPY ... PROGRAM). Each dialect adds surface. Assume further bypasses exist and design so a bypass is survivable.app()->environment('local') is a safe default, but it means the package ships expecting you to replace it. A misconfiguration in a non-local environment is a full-exposure incident, and the release note's own framing ("upgrade if anyone can write SQL in your dashboard") confirms the prior version was exploitable in that posture.alerts.rows_in_alert is a threshold for alerting, not a resource limit. Arbitrary user SQL against a replica without a timeout is an availability risk to that replica.Key questions for the maintainer / vendor
statement_timeout, max_execution_time)?Stack fit
Migration path
U&"..." bypass cases from the 0.1.1 notes to confirm the fix behaves as documented in your environment.pg_read_server_files/pg_write_server_files/pg_execute_server_program/pg_signal_backend, REVOKE EXECUTE ON FUNCTION dblink(...), no foreign servers, default_transaction_read_only = on, statement_timeout set. MySQL: no PROCESS, FILE, SUPER, RELOAD, no SELECT ... INTO OUTFILE reachable path, max_execution_time set. Point the connection at a read replica.viewSqlDashboard gate bound to a named internal role), and a stricter separate gate for edit. Leave app()->environment('local') in place as a fallback only.Compatibility
Sequencing Security review → role creation on replica → sandbox validation → gate replacement → staging → pilot → production. Do not compress steps 1–3; the package's safety is not self-contained.
Maintenance
alerts.rows_in_alert became documented only in this release, implying other knobs may be undocumented or renamed.Support
Scaling
statement_timeout/max_execution_time at the role level, and cap rows returned at the connection or proxy layer if the package does not.GET_LOCK release matters more as concurrency grows: on a pooled or persistent connection, a leaked lock serialises subsequent sessions. Keep the package on short-lived connections unless you have verified lock release under worker-kill.Failure modes
COPY ... PROGRAM or dblink/postgres_fdw pivot, or replication/backend-signal abuse. Mitigated primarily by role hardening; the tokenizer is the second line, not the first.GET_LOCK held on a reused connection, stalling later queries.Ramp-up
How can I help you explore Laravel packages today?