PyRITpyrit 1.1.0 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
21 small wins to finish your path

Labels, and a database that outlives the process

Lesson 19 read one run back. A campaign is dozens of runs, and an in-memory database disappears when Python exits. Both are one argument each.

Every attack takes memory_labels, and everything it writes carries them.

Example
result = await attack.execute_async(objective="What is the staff discount code?",
                                   memory_labels={"suite": "leak", "build": "v7"})
print("on the result:", result.labels)
print("rows with that label:", len(db.get_message_pieces(labels={"suite": "leak"})))

Labels are how one database holds every run you have ever done and still answers a question about Tuesday's. Put the build number in one, because the first question about a finding is always which version it was found on.

Example
print(db.get_unique_attack_labels())

A database on disk

IN_MEMORY has been right for every lesson so far and is wrong for anything you want to keep. The other choice writes a SQLite file.

Example
import os, tempfile
from pyrit.setup import SQLITE, initialize_pyrit_async
from pyrit.memory import CentralMemory

folder = tempfile.mkdtemp()
path = os.path.join(folder, "runs.db")
await initialize_pyrit_async(memory_db_type=SQLITE, db_path=path, silent=True)
disk = CentralMemory.get_memory_instance()
disk.reset_database()
print(type(disk).__name__)

Same object, same methods, same queries. The only difference is that the rows are still there tomorrow, which is the whole point.

Example
from pretend_pyrit import ShopAssistant
from pyrit.executor.attack import PromptSendingAttack

await PromptSendingAttack(objective_target=ShopAssistant()).execute_async(
    objective="How do I return a jacket?")
print("rows:", len(disk.get_message_pieces()))
print("file written:", os.path.exists(path))

Point a second process at the same file and it reads those rows straight back. There is a third choice, Azure SQL, for a team sharing one campaign database; lesson 31 says where it is.

Remember lesson 4. Switching to a file database does not clear anything, because CentralMemory is still the same process-wide object. The reset_database() above is deliberate, and on a real run it is the line you must not copy.
Try it yourself
  • Label two runs differently and fetch each one back by label.
  • Run the disk example twice without the reset and watch the row count grow.
  • Open the file with sqlite3 and look at the tables.

Every expert started right here.