Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
7ffeb71
perf(schemaview): incremental walker prototype (opt-in)
asheshv Jun 3, 2026
a232538
fix(schemaview): deferred-dep protocol + DataGridView hardening
asheshv Jun 3, 2026
9a75574
feat(schemaview): divergence canary for incremental walkers
asheshv Jun 3, 2026
d22a249
feat(schemaview): schema registry + audit harness ratchet
asheshv Jun 3, 2026
e00a033
test(schemaview): Playwright UI smoke for incremental walker + canary
asheshv Jun 3, 2026
986e0b6
fix(schemaview): production-flip hardening
asheshv Jun 3, 2026
a1436cf
fix(docker): make CAP_NET_BIND_SERVICE optional for restricted runtim…
asheshv May 28, 2026
4701f46
test(schemaview): properties mode + nested-fieldset audit + all-k rot…
asheshv Jun 3, 2026
b3ba446
test(schemaview): property-based fuzzing for the audit harness
asheshv Jun 3, 2026
86a9259
ci(schemaview): wire canary tree-shake + Playwright UI smoke
asheshv Jun 3, 2026
954d877
Merge remote-tracking branch 'origin/master' into dev/incremental-audit
asheshv Jun 3, 2026
9d6d48b
perf(schemaview): enable incremental option/validation walks by default
asheshv Jun 1, 2026
97bde2c
test(perf-bench): INCREMENTAL_OFF env var for A/B comparison
asheshv Jun 2, 2026
b118324
fix(ci): lint cleanup + uninstall pre-installed PG in UI smoke
asheshv Jun 3, 2026
e9e5ae1
Merge branch 'dev/incremental-flip' into dev/incremental-audit
asheshv Jun 3, 2026
51e7ceb
fix(ci): initialise pgAdmin config DB before load-servers
asheshv Jun 3, 2026
5f41f19
fix(ci): seed table + function for edit-mode smoke
asheshv Jun 3, 2026
cdeef07
fix(schemaview): drop unused catch bindings + surface fuzzer error msg
asheshv Jun 3, 2026
96ce7e9
fix(lint): proper fixes for warnings instead of suppressions
asheshv Jun 3, 2026
5903c02
fix(schemaview): drop scripts/ ignore + recurse nested-fieldset + laz…
asheshv Jun 3, 2026
a423329
fix(schemaview): aggressive-review iterations 1+3 fixes
asheshv Jun 4, 2026
b4005d9
test(perf-bench): extended UI smoke (15 dialogs) + visual regression
asheshv Jun 4, 2026
88bba03
test(perf-bench): address aggressive-review findings on extended smoke
asheshv Jun 4, 2026
03f63ba
test(perf-bench): apply iteration-5 review fixes
asheshv Jun 4, 2026
f38f1a4
docs(perf-bench): document PG max_connections + mock-pivot findings
asheshv Jun 4, 2026
7b8efdc
test(perf-bench): expand visual regression to 20 dialogs
asheshv Jun 4, 2026
bcad666
test(perf-bench): address detailed-review findings on extended smoke …
asheshv Jun 4, 2026
cf158f9
test(perf-bench): upgrade 15 smoke specs from mount-only to interacti…
asheshv Jun 4, 2026
2b7d616
fix(schemaview): walker missed pre-existing collection rows in increm…
asheshv Jun 4, 2026
ce3878e
fix(perf-bench): tree.selected() drift in navigation helpers
asheshv Jun 5, 2026
dfce814
test(perf-bench): per-test disconnect, debug instrumentation, paralle…
asheshv Jun 5, 2026
2c65393
test(perf-bench): address static-review findings
asheshv Jun 5, 2026
fe94828
test(perf-bench): per-platform visual baselines + new-row cell-fill
asheshv Jun 5, 2026
ab3913d
Merge remote-tracking branch 'origin/master' into dev/incremental-audit
asheshv Jun 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/workflows/check-canary-treeshake.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Verify canary tree-shake

# Builds a non-canary production bundle (CANARY_BUILD unset) and
# greps the resulting app.bundle.js for canary-only symbols. If any
# appear, the build-time DefinePlugin gate failed and the canary
# (~7 KiB) is shipping to end users along with the 2x walk cost on
# every keystroke. The script exits non-zero on any leak.
#
# Lightweight: no PostgreSQL service, no pgAdmin runtime, no Python.
# Just node + webpack + grep. Runs on every PR + master push.

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

workflow_dispatch:

concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
cancel-in-progress: true

jobs:
verify-canary-treeshake:
runs-on: ubuntu-22.04

steps:
- uses: actions/setup-node@v4
with:
node-version: '20.x'

- uses: actions/checkout@v4

- name: Upgrade yarn
run: |
yarn set version berry
yarn set version 4

- name: Install Node modules
run: |
cd web
yarn install

- name: Build NON-canary production bundle
run: |
cd web
# CANARY_BUILD intentionally NOT set — DefinePlugin should
# substitute process.env.__CANARY_BUILD__ → literal false
# and webpack should DCE the canary path + tree-shake the
# canary module's import.
NODE_ENV=production NODE_OPTIONS=--max-old-space-size=4096 \
./node_modules/.bin/webpack --config webpack.config.js

- name: Verify canary is tree-shaken
run: |
cd web
./scripts/verify-canary-treeshake.sh

- name: Archive bundle on failure (for triage)
if: failure()
uses: actions/upload-artifact@v4
with:
name: leaked-canary-bundle
path: web/pgadmin/static/js/generated/app.bundle.js
if-no-files-found: ignore
315 changes: 315 additions & 0 deletions .github/workflows/run-schemaview-ui-smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,315 @@
name: SchemaView UI smoke (Playwright)

# Runs the audit-smoke.spec.js Playwright tests against a real
# pgAdmin instance with __INCREMENTAL_AUDIT__ + __throw_on_canary
# _divergence__ enabled. Asserts no canary divergence across 5
# dialog flows (3 create + 2 edit).
#
# Synthetic Jest tests cover 87 schemas × 3 modes via the harness,
# but only a real browser exercises the production DepListener
# wiring + fixedRows async resolution + parallel-promise React
# batching that triggered three of this branch's bug fixes. This
# is the last line of defense before flipping the walker on.

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

workflow_dispatch:

concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
cancel-in-progress: true

jobs:
schemaview-ui-smoke:
runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '20.x'

- uses: actions/setup-python@v5
with:
python-version: '3.11'

# PostgreSQL setup — mirrors run-feature-tests-pg.yml.
- name: Setup the PGDG APT repo
run: |
sudo sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -

# ubuntu-22.04 runners come with an older PostgreSQL pre-
# installed. Dropping its cluster + removing the package
# before installing PG 16 ensures /etc/postgresql/16/main/
# is created cleanly by the new install (without this step,
# the pg_hba.conf path doesn't exist and the next step fails).
- name: Uninstall any pre-installed PostgreSQL
run: |
if [ -n "$(ls /etc/postgresql/*/*/postgresql.conf 2>/dev/null)" ]; then
installed_pg_version=$( pg_config --version | cut -d ' ' -f 2 | cut -d '.' -f 1 )
echo "Found pre-installed PostgreSQL $installed_pg_version; removing"
if [ "$installed_pg_version" != "16" ]; then
sudo pg_dropcluster $installed_pg_version main --stop || true
sudo apt-get -y remove "postgresql-${installed_pg_version}" || true
fi
fi

- name: Install PostgreSQL 16
run: |
sudo apt update
sudo apt install -y libpq-dev libffi-dev libssl-dev libkrb5-dev zlib1g-dev postgresql-16

- name: Start PostgreSQL on port 5916
run: |
sudo su -c "echo 'local all all trust' > /etc/postgresql/16/main/pg_hba.conf"
sudo su -c "echo 'host all all 127.0.0.1/32 trust' >> /etc/postgresql/16/main/pg_hba.conf"
sudo sed -i "s/port = 543[0-9]/port = 5916/g" /etc/postgresql/16/main/postgresql.conf
sudo su - postgres -c "/usr/lib/postgresql/16/bin/postgres -D /var/lib/postgresql/16/main -c config_file=/etc/postgresql/16/main/postgresql.conf &"
until sudo runuser -l postgres -c "pg_isready -p 5916" 2>/dev/null; do
>&2 echo "Postgres unavailable - sleeping 2s"
sleep 2
done

# pgAdmin Python deps.
- name: Install Python dependencies
run: |
python -m venv venv
. venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt

# config_local.py: desktop mode, no master password, no OS
# secret storage — so the smoke can drive the
# "Connect to Server" password prompt without ever hitting
# an Unlock Saved Passwords modal.
- name: Create pgAdmin config + test paths
run: |
mkdir -p var
cat <<'EOF' > web/config_local.py
from config import *

DEBUG = True
SERVER_MODE = False
MASTER_PASSWORD_REQUIRED = False
USE_OS_SECRET_STORAGE = False
UPGRADE_CHECK_ENABLED = False
CONSOLE_LOG_LEVEL = DEBUG
FILE_LOG_LEVEL = DEBUG
DEFAULT_SERVER = '127.0.0.1'

import os
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
LOG_FILE = ROOT + '/var/pgadmin4.log'
SESSION_DB_PATH = ROOT + '/var/sessions'
STORAGE_DIR = ROOT + '/var/storage'
SQLITE_PATH = ROOT + '/var/pgadmin4.db'
AZURE_CREDENTIAL_CACHE_DIR = ROOT + '/var/azurecredentialcache'
EOF

# CI's fresh PG 16 database is empty — no tables, no functions
# to "Edit Properties" on. The Edit-mode smoke specs need at
# least one child of each type under the default `postgres`
# database. Pre-create them so the smoke has real edit-mode
# targets.
#
# Covers all 15 Edit-mode specs in audit-smoke-extended.spec.js
# plus the 2 in audit-smoke.spec.js (Edit Table, Edit Function).
# Edit Role / Edit Tablespace / Edit Type pass without seed
# because every PG install ships with at least one of each.
- name: Seed schema objects for edit-mode smoke
run: |
PGPASSWORD= psql -h 127.0.0.1 -p 5916 -U postgres -d postgres -c "
-- Original 2 (audit-smoke.spec.js Edit Table / Function)
CREATE TABLE IF NOT EXISTS audit_smoke_table (
id integer PRIMARY KEY,
name text NOT NULL
);
CREATE OR REPLACE FUNCTION audit_smoke_func() RETURNS integer AS \$\$
SELECT 1;
\$\$ LANGUAGE sql IMMUTABLE;

-- Extended Edit-mode prerequisites (12 new):

CREATE OR REPLACE VIEW audit_smoke_view AS
SELECT id, name FROM audit_smoke_table;

CREATE MATERIALIZED VIEW IF NOT EXISTS audit_smoke_mview AS
SELECT id, name FROM audit_smoke_table;

CREATE SEQUENCE IF NOT EXISTS audit_smoke_seq;

DO \$\$ BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'audit_smoke_type') THEN
CREATE TYPE audit_smoke_type AS (a integer, b text);
END IF;
END \$\$;

DO \$\$ BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'audit_smoke_domain') THEN
CREATE DOMAIN audit_smoke_domain AS integer CHECK (VALUE >= 0);
END IF;
END \$\$;

CREATE OR REPLACE PROCEDURE audit_smoke_proc() LANGUAGE plpgsql
AS \$\$ BEGIN NULL; END; \$\$;

DO \$\$ BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_proc WHERE proname = 'audit_smoke_agg'
) THEN
CREATE AGGREGATE audit_smoke_agg (integer) (
SFUNC = int4pl, STYPE = integer, INITCOND = '0'
);
END IF;
END \$\$;

CREATE EXTENSION IF NOT EXISTS postgres_fdw;
DO \$\$ BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_foreign_server WHERE srvname = 'audit_smoke_fsrv'
) THEN
CREATE SERVER audit_smoke_fsrv
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host '127.0.0.1', dbname 'postgres');
END IF;
END \$\$;
CREATE FOREIGN TABLE IF NOT EXISTS audit_smoke_ftable (
id integer, name text
) SERVER audit_smoke_fsrv OPTIONS (table_name 'audit_smoke_table');

DO \$\$ BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_collation WHERE collname = 'audit_smoke_coll') THEN
CREATE COLLATION audit_smoke_coll (locale = 'C');
END IF;
END \$\$;

DO \$\$ BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_ts_config WHERE cfgname = 'audit_smoke_fts') THEN
CREATE TEXT SEARCH CONFIGURATION audit_smoke_fts (COPY = english);
END IF;
END \$\$;

CREATE OR REPLACE FUNCTION audit_smoke_tgfn() RETURNS trigger
LANGUAGE plpgsql AS \$\$ BEGIN RETURN NEW; END; \$\$;

DROP TRIGGER IF EXISTS audit_smoke_trig ON audit_smoke_table;
CREATE TRIGGER audit_smoke_trig BEFORE INSERT ON audit_smoke_table
FOR EACH ROW EXECUTE FUNCTION audit_smoke_tgfn();

CREATE INDEX IF NOT EXISTS audit_smoke_idx
ON audit_smoke_table (name);
"

# Initialise pgAdmin's config SQLite. load-servers below needs
# the DB to already exist — it doesn't auto-create. (Locally
# verified: load-servers on a missing SQLite path errors with
# "SQLite database file does not exist." before populating.)
- name: Initialise pgAdmin config DB
run: |
. venv/bin/activate
cd web && python setup.py setup-db

# Pre-register a server in pgAdmin's SQLite via setup.py
# load-servers. The smoke spec's ensureServerRegistered helper
# looks for an existing server in the tree; without this it
# falls back to whatever's there (nothing in fresh CI).
- name: Seed test server in pgAdmin SQLite
run: |
cat <<'EOF' > /tmp/servers.json
{
"Servers": {
"1": {
"Name": "CI-PG16",
"Group": "Servers",
"Port": 5916,
"Username": "postgres",
"Host": "127.0.0.1",
"MaintenanceDB": "postgres",
"SSLMode": "prefer"
}
}
}
EOF
. venv/bin/activate
cd web && python setup.py load-servers /tmp/servers.json

# Yarn + Node modules.
- name: Upgrade yarn
run: |
yarn set version berry
yarn set version 4

- name: Install Node modules
run: |
cd web
yarn install

# CANARY build — keeps the canary IN the bundle for the audit.
- name: Build canary bundle
run: |
cd web
CANARY_BUILD=true NODE_ENV=production \
NODE_OPTIONS=--max-old-space-size=4096 \
./node_modules/.bin/webpack --config webpack.config.js

# Start pgAdmin in the background.
- name: Start pgAdmin
run: |
. venv/bin/activate
cd web
nohup python pgAdmin4.py > ../var/pgadmin-stdout.log 2>&1 &
# Wait for /browser/ to respond.
for i in $(seq 1 30); do
if curl -fsS -o /dev/null http://127.0.0.1:5050/browser/; then
echo "pgAdmin up"
break
fi
sleep 2
done
curl -fsS -o /dev/null http://127.0.0.1:5050/browser/

# Playwright (browser install + smoke run).
- name: Install Playwright deps
run: |
cd web/regression/perf-bench
yarn install
./node_modules/.bin/playwright install --with-deps chromium

- name: Run audit-smoke
env:
PGADMIN_URL: http://127.0.0.1:5050/browser/
PGHOST: 127.0.0.1
PGPORT: '5916'
PGUSER: postgres
PGPASSWORD: ''
PGDATABASE: postgres
PGADMIN_SERVER_NAME: CI-PG16
run: |
cd web/regression/perf-bench
./node_modules/.bin/playwright test audit-smoke --reporter=line

- name: Archive pgAdmin server log
if: success() || failure()
uses: actions/upload-artifact@v4
with:
name: pgadmin-smoke-log
path: |
var/pgadmin4.log
var/pgadmin-stdout.log
if-no-files-found: ignore

- name: Archive Playwright trace + screenshots on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-smoke-failure
path: |
web/regression/perf-bench/playwright-report
web/regression/perf-bench/test-results
if-no-files-found: ignore
Loading
Loading