mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-08-21 15:12:26 +02:00
## Summary - Add `LANGGRAPH_STRICT_MSGPACK=true` guidance to `JsonPlusSerializer` docstring and inline comments - Update the warning message emitted for unregistered types to mention the env var - Add module docstring to `_msgpack.py` explaining the safety controls - Add Security sections to checkpoint, checkpoint-postgres, and checkpoint-sqlite READMEs ## Context Multiple security advisories have reported the same msgpack deserialization pattern (`ext_hook` → `importlib.import_module` → `getattr` → call). The underlying behavior is documented in the repo's threat model as T1, but the `LANGGRAPH_STRICT_MSGPACK` env var that mitigates it is not surfaced in user-facing docs, docstrings, or warning messages. This PR closes that gap. ## Test plan - [x] Verify READMEs render correctly on GitHub (callout boxes use `> [!IMPORTANT]` syntax) - [x] Verify `JsonPlusSerializer` docstring renders in IDE tooltips - [x] Confirm warning message format: `LANGGRAPH_STRICT_MSGPACK=true PYTHON_CMD 2>&1 | grep -i strict` --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
94 lines
2.5 KiB
Markdown
94 lines
2.5 KiB
Markdown
# LangGraph SQLite Checkpoint
|
|
|
|
Implementation of LangGraph CheckpointSaver that uses SQLite DB (both sync and async, via `aiosqlite`)
|
|
|
|
## Security
|
|
|
|
> [!IMPORTANT]
|
|
> Set `LANGGRAPH_STRICT_MSGPACK=true` or pass an explicit `allowed_msgpack_modules` list when creating your checkpointer. This restricts checkpoint deserialization to known-safe types, preventing code execution if the database is compromised. See the [langgraph-checkpoint README](https://github.com/langchain-ai/langgraph/tree/main/libs/checkpoint#serde) for details.
|
|
|
|
## Usage
|
|
|
|
```python
|
|
from langgraph.checkpoint.sqlite import SqliteSaver
|
|
|
|
write_config = {"configurable": {"thread_id": "1", "checkpoint_ns": ""}}
|
|
read_config = {"configurable": {"thread_id": "1"}}
|
|
|
|
with SqliteSaver.from_conn_string(":memory:") as checkpointer:
|
|
checkpoint = {
|
|
"v": 4,
|
|
"ts": "2024-07-31T20:14:19.804150+00:00",
|
|
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
|
|
"channel_values": {
|
|
"my_key": "meow",
|
|
"node": "node"
|
|
},
|
|
"channel_versions": {
|
|
"__start__": 2,
|
|
"my_key": 3,
|
|
"start:node": 3,
|
|
"node": 3
|
|
},
|
|
"versions_seen": {
|
|
"__input__": {},
|
|
"__start__": {
|
|
"__start__": 1
|
|
},
|
|
"node": {
|
|
"start:node": 2
|
|
}
|
|
},
|
|
}
|
|
|
|
# store checkpoint
|
|
checkpointer.put(write_config, checkpoint, {}, {})
|
|
|
|
# load checkpoint
|
|
checkpointer.get(read_config)
|
|
|
|
# list checkpoints
|
|
list(checkpointer.list(read_config))
|
|
```
|
|
|
|
### Async
|
|
|
|
```python
|
|
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
|
|
|
|
async with AsyncSqliteSaver.from_conn_string(":memory:") as checkpointer:
|
|
checkpoint = {
|
|
"v": 4,
|
|
"ts": "2024-07-31T20:14:19.804150+00:00",
|
|
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
|
|
"channel_values": {
|
|
"my_key": "meow",
|
|
"node": "node"
|
|
},
|
|
"channel_versions": {
|
|
"__start__": 2,
|
|
"my_key": 3,
|
|
"start:node": 3,
|
|
"node": 3
|
|
},
|
|
"versions_seen": {
|
|
"__input__": {},
|
|
"__start__": {
|
|
"__start__": 1
|
|
},
|
|
"node": {
|
|
"start:node": 2
|
|
}
|
|
},
|
|
}
|
|
|
|
# store checkpoint
|
|
await checkpointer.aput(write_config, checkpoint, {}, {})
|
|
|
|
# load checkpoint
|
|
await checkpointer.aget(read_config)
|
|
|
|
# list checkpoints
|
|
[c async for c in checkpointer.alist(read_config)]
|
|
```
|