Commit graph

2 commits

Author SHA1 Message Date
lekss361
6507a5af64 fixup(tradein): address deep-review BLOCK findings on FDW PR
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.
2026-05-24 11:50:51 +03:00
lekss361
698ef4f003 feat(tradein): postgres_fdw live read of gendesign.cad_buildings (replaces snapshot)
Replaces tradein.cad_buildings manual snapshot (36k rows, frozen 2026-05-22) with
live postgres_fdw foreign table reading gendesign.v_tradein_cad_buildings directly.
Also reverts PR #492 HTTP-based cadastral.py — superseded by FDW.

Architecture:
- gendesign DB: new role tradein_fdw_reader + flat view v_tradein_cad_buildings
  (EKB-only slice of cad_buildings with lat/lon flattened from geom)
- networks: gendesign-postgres added to gendesign_shared (alias);
  tradein-postgres added to gendesign_shared for FDW connect
- tradein DB: postgres_fdw extension + FOREIGN TABLE gendesign_cad_buildings
- tradein backend: startup hook creates/refreshes USER MAPPING with password
  from env GENDESIGN_FDW_PASSWORD (password rotation handled via restart)
- geocoder.py: cadastral primary for forward + reverse + suggest;
  Yandex/Nominatim fallback. reverse_geocode wraps Nominatim in try/except —
  no more HTTPStatusError → 500.
- house_metadata.py and trade_in.py admin stats switched to foreign table
- DROP TABLE cad_buildings in tradein (legacy snapshot removed entirely)
- import-cadastre.sh deleted (no manual sync needed)

Fixes:
- /trade-in/api/v1/geocode/reverse 500 (Nominatim ban → no fallback)
- estimate confidence_explanation=address_not_geocoded for addresses in our
  cadastre (e.g. Хохрякова 81) that Nominatim doesn't return

Deploy ordering: main migration 100_tradein_fdw_role.sql adds role+view first
(strict deploy.yml). Tradein next deploy applies 060_postgres_fdw_extension.sql
and 061_drop_legacy_cad_buildings.sql (idempotent, errors ignored). Tradein
backend startup creates USER MAPPING when env var present. Verify post-deploy
with: docker exec tradein-postgres psql -U tradein -d tradein -c \
  "SELECT count(*) FROM gendesign_cad_buildings"  # expect ~36k EKB buildings.
2026-05-24 11:13:44 +03:00