Critical:
- data/sql/100_tradein_fdw_role.sql — remove hardcoded password literal;
role created LOGIN only; explicit REVOKE perimeter on all
tables/sequences/functions in public; only v_tradein_cad_buildings grant
remains. Password is now set by .forgejo/workflows/deploy.yml ALTER ROLE
bootstrap step reading GENDESIGN_FDW_PASSWORD from backend/.env.runtime.
- tradein-mvp/backend/app/core/fdw.py — strict regex whitelist on password
([A-Za-z0-9_-]{32,256}) before inlining into DDL; ValueError on mismatch
(no password in error message); pg_user_mappings query corrected for
PUBLIC mapping (usename IS NULL); commit wrapped in try/rollback.
High:
- 060_postgres_fdw_extension.sql — connect_timeout='3' added to FOREIGN
SERVER; ALTER SERVER ADD/SET fallback for re-apply path.
- geocoder.py — _cadastral_forward_sync / _cadastral_reverse_sync wrapped in
asyncio.to_thread to avoid blocking event loop on FDW outage.
Tests:
- 3 new test_cadastral_reverse.py cases: SQL injection password rejected,
short password rejected, valid hex password accepted with mapping creation.
Old password 40473b7c... remains in git history at 698ef4f (force-push
forbidden) — but the role was never created with it on prod (SQL not
deployed), so abandoned. New password 72df... lives only in VPS env files
and vault meta/00_credentials.md.
43 lines
1.5 KiB
PL/PgSQL
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;
|