gendesign/tradein-mvp/backend/data/sql/060_postgres_fdw_extension.sql
lekss361 94cf199276
Some checks failed
Deploy Trade-In / changes (push) Successful in 5s
Deploy / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Successful in 26s
Deploy Trade-In / build-backend (push) Successful in 47s
Deploy / build-frontend (push) Successful in 29s
Deploy / build-backend (push) Successful in 1m24s
Deploy Trade-In / deploy (push) Successful in 40s
Deploy / build-worker (push) Successful in 2m57s
Deploy / deploy (push) Failing after 37s
feat(tradein): postgres_fdw live read of gendesign.cad_buildings (replaces snapshot) (#493)
Replaces tradein.cad_buildings snapshot with live postgres_fdw foreign table reading gendesign.v_tradein_cad_buildings. Fixes /trade-in/api/v1/geocode/reverse 500 (Nominatim ban) and address_not_geocoded for cadastre addresses (e.g. Хохрякова 81).

Security (deep-review fixes):
- 100_tradein_fdw_role.sql: passwordless CREATE ROLE; password set by deploy.yml ALTER ROLE bootstrap reading GENDESIGN_FDW_PASSWORD from backend/.env.runtime (via psql :'pw' var → format %L — injection-safe).
- core/fdw.py: regex whitelist [A-Za-z0-9_-]{32,256} on password, ValueError without echoing value, try/rollback on commit.
- 060_postgres_fdw_extension.sql: connect_timeout='3' on FOREIGN SERVER + ALTER ADD/SET fallback.
- geocoder.py: _cadastral_forward_sync / _cadastral_reverse_sync wrapped in asyncio.to_thread.
- 100_*.sql: REVOKE ALL ON ALL TABLES/SEQUENCES/FUNCTIONS IN SCHEMA public; only GRANT SELECT on v_tradein_cad_buildings.
- pg_user_mappings query handles PUBLIC mapping (usename IS NULL).

Tests: 3 SQL-injection guards on ensure_fdw_user_mapping + rewritten cadastral suite.
2026-05-24 08:57:30 +00:00

43 lines
1.5 KiB
PL/PgSQL

-- postgres_fdw extension for tradein → gendesign live reads.
-- Idempotent. Server config only (no USER MAPPING — that's set by backend startup with env password).
BEGIN;
CREATE EXTENSION IF NOT EXISTS postgres_fdw;
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_foreign_server WHERE srvname = 'gendesign_remote') THEN
CREATE SERVER gendesign_remote
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'gendesign-postgres', dbname 'gendesign', port '5432',
extensions 'postgis', connect_timeout '3');
ELSE
-- Update existing server: add connect_timeout if missing, or set if already present.
BEGIN
ALTER SERVER gendesign_remote OPTIONS (ADD connect_timeout '3');
EXCEPTION WHEN OTHERS THEN
ALTER SERVER gendesign_remote OPTIONS (SET connect_timeout '3');
END;
END IF;
END$$;
-- Drop existing foreign table if mistakenly created with wrong schema (idempotent re-create below)
DROP FOREIGN TABLE IF EXISTS gendesign_cad_buildings;
CREATE FOREIGN TABLE gendesign_cad_buildings (
cad_num text,
readable_address text,
year_built integer,
floors integer,
area_m2 numeric,
purpose text,
lat double precision,
lon double precision
)
SERVER gendesign_remote
OPTIONS (schema_name 'public', table_name 'v_tradein_cad_buildings');
COMMENT ON FOREIGN TABLE gendesign_cad_buildings IS
'Live view of gendesign.cad_buildings (EKB only). USER MAPPING managed by backend startup.';
COMMIT;