
Sicherheitsforschungslabor: Reproduktion von CVE-2025-52467 (pgai pull_request_target-Workflow-Codeausführung / GITHUB_TOKEN-Exfiltration) — Schnappschuss von timescale/pgai
Automatisiertes Forschungsobjekt — nicht das Upstream-Projekt.
Dieses Repository ist ein Wegwerf-Labor, das von einer automatisierten Testumgebung für eine Masterarbeit an der Université Laval zur Reproduktion veröffentlichter GitHub-Actions- Workflow-Schwachstellen erstellt wurde. Es ist eine wörtliche Momentaufnahme von
timescale/pgaibeim Commit2a209b058c60823b57e8b7775b10244ff340eb8b(2025-05-14), weiterverbreitet unter der eigenen Lizenz dieses Projekts, deren Datei unverändert in dieser Momentaufnahme enthalten ist.Das Upstream-Projekt ist nicht beteiligt, wird niemals angegriffen, und die hier untersuchte Schwachstelle ist bereits öffentlich. Jedes Secret und jede Variable in diesem Repository ist ein zufällig generierter Dummy-Wert — es ist kein echtes Zugangsdatum vorhanden. Aktionsreferenzen und Runner-Images sind auf das fixiert, was sie am 2025-05-14 aufgelöst haben; siehe
pinning.mdin der Testumgebungsausgabe für jede an der Momentaufnahme vorgenommene Änderung.Fragen oder Einwände: [email protected]
Eine Python-Bibliothek, die PostgreSQL in eine robuste, produktionsreife Abruf-Engine für RAG- und Agentic-Anwendungen verwandelt.
🔄 Automatisches Erstellen und Synchronisieren von Vektor-Embeddings aus PostgreSQL-Daten und S3-Dokumenten. Embeddings aktualisieren sich automatisch, wenn sich Daten ändern.
🔍 Leistungsstarke Vektor- und semantische Suche mit pgvector und pgvectorscale.
🛡️ Sofort produktionsreif: Unterstützt Stapelverarbeitung für effiziente Embedding-Erzeugung, mit integrierter Behandlung von Modellfehlern, Ratenbegrenzungen und Latenzspitzen.
🐘 Funktioniert mit jeder PostgreSQL-Datenbank, einschließlich Timescale Cloud, Amazon RDS, Supabase und mehr.
Grundlegende Architektur: Das System besteht aus einer Anwendung, die Sie schreiben, einer PostgreSQL-Datenbank und zustandslosen Vectorizer-Workern. Die Anwendung definiert eine Vectorizer-Konfiguration, um Daten aus Quellen wie PostgreSQL oder S3 einzubetten. Die Worker lesen diese Konfiguration, verarbeiten die Datenwarteschlange zu Embeddings und in Blöcke aufgeteiltem Text und schreiben die Ergebnisse zurück. Die Anwendung fragt diese Daten dann ab, um RAG und semantische Suche zu betreiben.
Die Hauptstärke dieser Architektur liegt in ihrer Widerstandsfähigkeit: Datenänderungen durch die Anwendung sind vom Embedding-Prozess entkoppelt, sodass Fehler im Embedding-Dienst die Kern-Datenoperationen nicht beeinträchtigen.
Installieren Sie zuerst das pgai-Paket.``` pip install pgai
Dann installiere die pgai-Datenbankkomponenten. Du kannst dies vom Terminal aus über die CLI oder in deinem Python-Anwendungscode mithilfe des pgai-Python-Pakets tun.```
# from the cli
pgai install -d <database-url>
# or from the python package, often done as part of your application setup
import pgai
pgai.install(DB_URL)
Diese Quickstart-Demonstration zeigt, wie pgai Vectorizer semantische Suche und RAG über PostgreSQL-Daten ermöglicht, indem Embeddings automatisch erstellt und synchronisiert werden, wenn sich Daten ändern.
Die entscheidende „Geheimzutat" von pgai Vectorizer ist sein deklarativer Ansatz zur Embedding-Generierung. Definieren Sie einfach Ihre Pipeline und lassen Sie Vectorizer die operative Komplexität der Synchronisierung von Embeddings übernehmen, selbst wenn Embedding- Endpunkte unzuverlässig sind. Sie können eine einfache Version der Pipeline wie folgt definieren:```sql CREATE TABLE IF NOT EXISTS wiki ( id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY, url TEXT NOT NULL, title TEXT NOT NULL, text TEXT NOT NULL )
SELECT ai.create_vectorizer( 'wiki'::regclass, loading => ai.loading_column(column_name=>'text'), destination => ai.destination_table(target_table=>'wiki_embedding_storage'), embedding => ai.embedding_openai(model=>'text-embedding-ada-002', dimensions=>'1536') )
The vectorizer will automatically create embeddings for all the rows in the
`wiki` table, and, more importantly, will keep the embeddings synced with the
underlying data as it changes. **Think of it almost like declaring an index** on
the `wiki` table, but instead of the database managing the index datastructure
for you, the Vectorizer is managing the embeddings.
## Running the quick start
**Prerequisites:**
- A PostgreSQL database ([docker instructions](https://docs.timescale.com/self-hosted/latest/install/installation-docker/)).
- An OpenAI API key (we use openai for embedding in the quick start, but you can use [multiple providers](#supported-embedding-models)).
Create a `.env` file with the following:```
OPENAI_API_KEY=<your-openai-api-key>
DB_URL=<your-database-url>
Sie können den vollständigen Python-Code und die requirements.txt aus dem Quickstart-Beispiel herunterladen und im selben Verzeichnis wie die .env-Datei ausführen.
Pgai benötigt einige Katalogtabellen und -funktionen, die in der Datenbank installiert werden müssen. Dies erfolgt mithilfe der Funktion pgai.install, die die erforderlichen Komponenten im ai-Schema der Datenbank installiert.```python
pgai.install(DB_URL)
### Vektorizer erstellen
Dies definiert den Vektorizer, der dem System mitteilt, wie die Embeddings aus der `text`-Spalte in der `wiki`-Tabelle erstellt werden. Der Vektorizer erstellt eine View `wiki_embedding`, die wir für die Embeddings abfragen können (wie wir weiter unten sehen werden).```python
async def create_vectorizer(conn: psycopg.AsyncConnection):
async with conn.cursor() as cur:
await cur.execute("""
SELECT ai.create_vectorizer(
'wiki'::regclass,
if_not_exists => true,
loading => ai.loading_column(column_name=>'text'),
embedding => ai.embedding_openai(model=>'text-embedding-ada-002', dimensions=>'1536'),
destination => ai.destination_table(view_name=>'wiki_embedding')
)
""")
await conn.commit()
In diesem Beispiel führen wir den Vectorizer-Worker einmal aus, um die Embeddings für die vorhandenen Daten zu erstellen.```python worker = Worker(DB_URL, once=True) worker.run()
In einer realen Anwendung würden wir den Worker nicht jedes Mal manuell aufrufen, wenn wir die Embeddings erstellen möchten. Stattdessen würden wir den Worker im Hintergrund ausführen, und er würde kontinuierlich laufen und nach Arbeit vom Vectorizer pollen.
Sie können den Worker im Hintergrund über die Anwendung, die CLI oder Docker ausführen. Weitere Details finden Sie in der Dokumentation zum [Vectorizer-Worker](https://github.com/pvharmo2/gha-lab-e8902eccd3/blob/main/docs/vectorizer/worker.md).
### Durchsuchen Sie die Wiki-Artikel mithilfe der semantischen Suche
Dies ist eine standardmäßige pgvector-semantische Suche in PostgreSQL. Die Suche wird gegen die `wiki_embedding`-Sicht durchgeführt, die vom Vectorizer erstellt wird und alle Spalten der `wiki`-Tabelle sowie die `embedding`-Spalte und den Chunk-Text enthält. Diese Funktion gibt sowohl die gesamte `text`-Spalte aus der `wiki`-Tabelle als auch kleinere Textabschnitte zurück, die für die Abfrage am relevantesten sind.```python
@dataclass
class WikiSearchResult:
id: int
url: str
title: str
text: str
chunk: str
distance: float
async def _find_relevant_chunks(client: AsyncOpenAI, query: str, limit: int = 1) -> List[WikiSearchResult]:
# Generate embedding for the query using OpenAI's API
response = await client.embeddings.create(
model="text-embedding-ada-002",
input=query,
encoding_format="float",
)
embedding = np.array(response.data[0].embedding)
# Query the database for the most similar chunks using pgvector's cosine distance operator (<=>)
async with pool.connection() as conn:
async with conn.cursor(row_factory=class_row(WikiSearchResult)) as cur:
await cur.execute("""
SELECT w.id, w.url, w.title, w.text, w.chunk, w.embedding <=> %s as distance
FROM wiki_embedding w
ORDER BY distance
LIMIT %s
""", (embedding, limit))
return await cur.fetchall()
Dieser Code ist bemerkenswert für das, was er nicht tut. Dies ist ein einfaches Einfügen eines neuen Artikels in die wiki-Tabelle. Wir mussten nichts Besonderes tun, um die Embeddings zu erstellen – der Vectorizer-Worker kümmert sich darum, die Embeddings zu aktualisieren, sobald sich die Daten ändern.```python
def insert_article_about_pgai(conn: psycopg.AsyncConnection):
async with conn.cursor(row_factory=class_row(WikiSearchResult)) as cur:
await cur.execute("""
INSERT INTO wiki (url, title, text) VALUES
('https://en.wikipedia.org/wiki/pgai', 'pgai', 'pgai is a Python library that turns PostgreSQL into the retrieval engine behind robust, production-ready RAG and Agentic applications. It does this by automatically creating vector embeddings for your data based on the vectorizer you define.')
""")
await conn.commit()
### RAG mit dem LLM durchführen
Dieser Code führt RAG mit dem LLM durch. Er verwendet die oben definierte Funktion `_find_relevant_chunks`, um die relevantesten Textabschnitte aus der Tabelle `wiki` zu finden, und nutzt dann das LLM, um eine Antwort zu generieren.```python
query = "What is the main thing pgai does right now?"
relevant_chunks = await _find_relevant_chunks(client, query)
context = "\n\n".join(
f"{chunk.title}:\n{chunk.text}"
for chunk in relevant_chunks
)
prompt = f"""Question: {query}
Please use the following context to provide an accurate response:
{context}
Answer:"""
response = await client.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [{ role: "user", content: prompt }],
})
print("RAG response:")
print(response.choices[0].message.content)
Weitere Schnellstart-Anleitungen finden Sie hier:
Erfahren Sie mehr über den Vectorizer:
Unsere pgai-Python-Bibliothek ermöglicht Ihnen die Arbeit mit Embeddings, die aus Ihren Daten generiert werden:
Sie können die Vektor-Embeddings für Folgendes verwenden:
Wir bieten außerdem eine PostgreSQL-Erweiterung an, die LLM-Modellaufrufe direkt aus SQL heraus durchführen kann. Dies ist häufig nützlich für Anwendungsfälle wie Klassifizierung, Zusammenfassung und Datenanreicherung Ihrer vorhandenen Daten.
Der Vectorizer ist darauf ausgelegt, flexibel und anpassbar zu sein. Jeder Vectorizer definiert eine Pipeline zum Erstellen von Embeddings aus Ihren Daten. Die Pipeline wird durch eine Reihe von Komponenten definiert, die nacheinander auf die Daten angewendet werden:
Die folgenden Modelle werden für das Einbetten unterstützt:
Das bloße Erstellen von Vektor-Embeddings ist einfach und unkompliziert. Die Herausforderung besteht darin, dass LLMs etwas unzuverlässig sind und die Endpunkte zeitweise Ausfälle und/oder eine verminderte Leistung aufweisen. Ein entscheidender Teil der ordnungsgemäßen Behandlung von Fehlern ist, dass Ihre primären Datenänderungsoperationen (INSERT, UPDATE, DELETE) nicht von der Embedding-Operation abhängig sein sollten. Andernfalls ist Ihre Anwendung jedes Mal nicht verfügbar, wenn der Endpunkt langsam ist oder ausfällt, und die Benutzererfahrung leidet darunter.
Normalerweise müssten Sie eine benutzerdefinierte MLops-Pipeline implementieren, um Endpunktfehler ordnungsgemäß zu behandeln. Dies umfasst in der Regel ein Queuing-System wie Kafka, spezialisierte Worker und andere Infrastruktur zur Verwaltung der Warteschlange und zum Wiederholen fehlgeschlagener Anfragen. Das ist viel Arbeit und es ist leicht, dabei Fehler zu machen.
Mit pgai können Sie das alles überspringen und sich auf die Entwicklung Ihrer Anwendung konzentrieren, da der Vectorizer die Embeddings für Sie verwaltet. Wir haben integrierte Queueing- und Retry-Logik, um die verschiedenen Fehlermodi zu behandeln, auf die Sie stoßen können. Da wir diese Arbeit im Hintergrund erledigen, sind die primären Datenänderungsoperationen nicht von der Embedding-Operation abhängig. Deshalb ist pgai sofort produktionsreif.
Viele spezialisierte Vektor-Datenbanken erstellen Embeddings für Sie. Sie versagen jedoch typischerweise, wenn Embedding-Endpunkte nicht verfügbar oder beeinträchtigt sind, und legen die Last der Fehlerbehandlung und Wiederholungsversuche wieder auf Sie.
Wir freuen uns über Beiträge zu pgai! Weitere Informationen finden Sie auf der Seite Mitwirken.
pgai befindet sich noch in einem frühen Stadium. Jetzt ist ein guter Zeitpunkt, um die Richtung dieses Projekts mitzugestalten; wir legen derzeit Prioritäten fest. Werfen Sie einen Blick auf die Liste der Funktionen, an denen wir arbeiten möchten. Sie können gerne kommentieren, die Liste erweitern oder am Discussions-Forum teilnehmen.
Um loszulegen, schauen Sie sich an, wie Sie beitragen können und wie Sie eine Entwicklungs-/Testumgebung einrichten.
Timescale ist ein PostgreSQL-Datenbankunternehmen. Weitere Informationen finden Sie unter timescale.com.
Timescale Cloud ist eine leistungsstarke, entwicklerorientierte Cloud-Plattform, die PostgreSQL-Dienste für die anspruchsvollsten KI-, Zeitreihen-, Analyse- und Event-Workloads bereitstellt. Timescale Cloud ist ideal für Produktionsanwendungen und bietet Hochverfügbarkeit, Streaming-Backups, Upgrades im Laufe der Zeit, Rollen und Berechtigungen sowie hohe Sicherheit.