Updates

Custom reports now stay in their own store

Custom reports used to run as the engine’s own database login. Now they run as a separate login that can only read — and on a platform, each store gets a login that reaches only that store.

What custom reports are

A custom report is a SQL query saved on the panel’s Reports screen, for questions only your shop has — which wholesale customers have not ordered since March, say.

RuleValue
Who can write onereports.write — only the owner role, by default
Who can run a saved onereports.read — owner, manager and staff, by default
What it may beOne SELECT or WITH statement
Limits15 seconds, 1,000 rows

Every run is a read-only transaction, always rolled back, so PostgreSQL refuses inserts, updates, deletes and schema changes. That has not changed.

What was wrong

A read-only transaction stops writes, but not PostgreSQL’s maintenance functions, which are plain SELECTs. So what a report could do came down to its login — the engine’s.

What changed

Reports now run on their own small connection pool, with their own login.

BeforeAfter
Login a report runs asThe engine’s ownA role granted only SELECT — gocommerce_reports by default
SuperuserYes, in both compose filesNo — doctor fails if it is
Ending the engine’s connections, replication slots, reading filesAllowed under a superuserRefused by PostgreSQL
Platform: another store’s tablesReadable by naming its schemaRefused
No reports login set upNot applicableReports do not run (reports_disabled)
ConnectionsShared with the engineUp to 4 per store, closed after use

On a platform, GOCOMMERCE_REPORTS_DATABASE_URL is a template. Booting a store creates its own login — reports_<store id>, prefixed with the -namespace if one is set — with the template’s password and read on that store’s schema only. It belongs to no other role, so it cannot switch into another store’s. It is dropped with the store. A test proves one store’s report can neither read another’s table nor take its role.

With no reports login, the feature is off; it never falls back to the engine’s login. Saved reports stay, and saving and listing still work.

What to do after upgrading

Custom reports stay off until you set up the login.

InstallDo this
New, with docker-compose.ymlSet REPORTS_DB_PASSWORD before the first start, and GOCOMMERCE_REPORTS_DATABASE_URL to log in as gocommerce_reports with it.
Existing single storeRun scripts/reports-role.sql once, then set GOCOMMERCE_REPORTS_DATABASE_URL (or -reports-db).
PlatformCreate the template role with -v grant_schema=no — docker-compose.platform.yml does so on a fresh volume from REPORTS_DB_PASSWORD. The platform’s login needs CREATEROLE. Existing stores get their own login on the next boot.

Turn custom reports on for an existing store

# once, as a superuser; add -v grant_schema=no on a platform
psql "$DATABASE_URL" -v reports_password="a-strong-password" -f scripts/reports-role.sql

# then, for the engine
GOCOMMERCE_REPORTS_DATABASE_URL=postgres://gocommerce_reports:a-strong-password@HOST:PORT/DB

Adapted from scripts/reports-role.sql. Safe to re-run, to change the password or re-grant after new tables.

On a single store, if the URL is set but cannot log in, the engine will not start. On a platform, a store whose own login cannot be set up keeps serving with reports off, and the platform logs an error.

gocommerce doctor, and Settings → Diagnostics in the panel, now run a “custom reports” check:

ResultWhat it means
warn — “disabled: no reports database role is configured”The feature is off. Safe.
warn — “custom reports run as …, the engine’s own database role”Give reports a separate role.
FAIL — “the custom-reports role is a superuser”Fix this first.
ok — “reports run as …, a non-superuser role”Set up as intended.

A warning leaves doctor reporting healthy. A failure makes it exit non-zero.

Who was affected

Every tagged release up to v1.2.0 runs reports the old way. The fix is on main and is not in a tagged release yet. If you run a platform, build from main rather than wait for the next release.

In both, only someone holding reports.write could write the SQL.

What it does not cover

Further reading

Chat on WhatsApp