Перейти к содержимому

Postgres как управляемый источник контекста

Коннектор содержимого postgres (olivares.pg-content) позволяет направить control plane на базу PostgreSQL и превратить её строки в управляемые документы знаний. Они проходят тот же pipeline, что и любой другой источник содержимого: redact → classify → chunk → embed → index → предоставление через MCP, с ACL для каждого документа и классификацией для каждого столбца.

Для операционных баз это аналог источников содержимого SaaS/хранилищ данных (gdrive, confluence, s3content, snowflake…). Но он не является двумя вещами:

  • Не pgaudit. pgaudit наблюдает рёбра доступа R/RW для карты доступа, но никогда не читает содержимое строк. pg-content материализует строки как документы. Это разные коннекторы для разных задач.
  • Не NL-to-SQL. Этот коннектор загружает строки как содержимое и не генерирует SQL из естественного языка во время запроса. (Некоторые конкуренты называют функцию text-to-SQL «базой знаний со структурированными данными», но это поверхность запросов агента, а не управляемый источник содержимого. Этот коннектор намеренно является вторым.)

Коннектор никогда не пишет в вашу базу и принуждает это на трёх независимых уровнях, чтобы запись была невозможной, а не просто нежелательной:

  1. Только запросы SELECT. Коннектор всегда строит лишь выражения SELECT. Если вы задаёте свой query, он проверяется как единственный запрос SELECT/WITH только для чтения. Второе выражение, изменяющий данные CTE (WITH x AS (DELETE …)), COPY, SELECT … INTO или любой DDL отклоняются deny-closed при Open.
  2. Сессия только для чтения. Каждое выражение выполняется в транзакции READ ONLY в сессии, открытой с default_transaction_read_only = on, поэтому PostgreSQL сам отказывает в записи. При Open коннектор проверяет, что сессия доступна только для чтения, и отказывается запускаться в противном случае. Это гарантия постуры, а не совет.
  3. Роль с минимальными привилегиями. Вы выдаёте коннектору роль, имеющую SELECT и ничего больше. См. эталонную роль ниже.

Эта защита сильнее, чем у всех управляемых конкурирующих сервисов, которые в документации представляют чтение без записи лишь как рекомендацию.

CREATE ROLE olivares_ro LOGIN PASSWORD '';
GRANT USAGE ON SCHEMA public TO olivares_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO olivares_ro;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO olivares_ro;
-- Never grant INSERT/UPDATE/DELETE/DDL. Optionally pin the role read-only:
ALTER ROLE olivares_ro SET default_transaction_read_only = on;

Для самой узкой области выдайте SELECT только на таблицы, которые хотите загружать.

Определите превращение строки в документ

Заголовок раздела «Определите превращение строки в документ»

Определение документа декларативно: вы указываете столбцы ключа, тела, заголовка, ACL, классификации и курсора синхронизации:

// OLIVARES_SOURCES_CONFIG — document sources live under "documents"
{
"documents": [
{
"name": "support-articles",
"kind": "postgres",
"config": {
"mode": "live",
"dsn": "vault:secret/data/pg-ro#dsn", // secret-store REFERENCE, never inline
"schema": "public",
"table": "kb_articles",
"key_columns": "id", // the stable document id
"body_columns": "title,body", // concatenated into the document body
"title_column": "title",
"updated_at_column": "updated_at", // drives incremental (delta) sync
"acl_columns": "owner_group", // → ACL "group:<value>"
"acl_prefix": "group:",
"classification_column": "sensitivity",
"sensitive_columns": "email,ssn", // → external label "pii:<column>"
"sensitive_label": "pii",
"metadata_columns": "url_path",
"sslmode": "require",
"statement_timeout": "30s",
"max_rows": "100000"
}
}
]
}

Вместо table можно указать query только для чтения (проверенный SELECT), например, чтобы присоединить таблицу ACL или отфильтровать публикуемые строки. Учётные данные всегда задаются ссылкой на хранилище секретов (vault:…, aws-secretsmanager:… и т. п.); секрет открытым текстом отклоняется.

Коннектор отображает только то, что выражает строка. ACL документа строится из значений объявленных acl_columns (например, столбец owner_groupgroup:eng). Коннектор не выдумывает ACL для строки, которой нет в источнике, и явно указывает ограничения:

СитуацияДействие коннектора
Столбец owner_group / ролиКаждое значение отображается в ссылку ACL (<acl_prefix><value>).
acl_columns не объявленыДокумент наследует ACL по умолчанию базы знаний, и извлечение по-прежнему её принуждает.
Row-level security (RLS) таблицыНеявно соблюдается: роль коннектора видит ровно те строки, которые ей разрешает RLS. Коннектор не реализует RLS повторно, а наследует её.
Разрешение, которое таблица не моделирует столбцомНевыводимо → не отображается. Если его нужно принуждать, смоделируйте столбец (или присоедините таблицу ACL через query).

В этом намеренное отличие от управляемых конкурентов, которые заставляют вручную создавать столбцы ACL и не предлагают passthrough RLS. Здесь столбцы ACL тоже отображаются вручную, но коннектор дополнительно соблюдает RLS и никогда не фабрикует отсутствующие в строке разрешения.

Перечислите чувствительные столбцы в sensitive_columns. Если в одном из них у строки есть значение, документ получает внешнюю метку "<sensitive_label>:<column>" (например, pii:ssn). Эти метки поступают в DLP извлечения и принуждаются deny-closed вместе с classification_column строки.

  • mode: live читает базу через пул только для чтения и поддерживает инкрементальную (delta) синхронизацию по курсору updated_at_column. Если курсор не настроен, fallback — сверка полного списка.
  • mode: export разбирает статический снимок строк (созданный вами вне системы JSON dump). Снимок никогда не представляется как live: источник честно сообщает свой режим.
  • Тело документа ограничено 1 МиБ; более крупная строка обрезается (streaming очень больших столбцов — последующая работа).
  • В заданном оператором query столбцу с именем, буквально совпадающим с ключевым словом SQL (например, update), нужен alias: гейт только для чтения работает deny-closed.
  • Коннектор читает содержимое; действия над базой вне области (пути записи нет по конструкции), как и CDC streaming и NL-to-SQL.

Коннектор поставляется с E2E на реальном соединении (-tags e2e, CI), который работает с настоящей PostgreSQL: проверяет сессию только для чтения при Open, загружает подготовленные строки с отображёнными ACL/классификацией и доказывает, что PostgreSQL отклоняет запись в сессии только для чтения. См. connectors/pgcontent/testdata/docker-compose.e2e.yml.