Vendors curry_core.py from Athena-Pro/Curry (with the str.format()/format_map() sandbox-escape fix from https://github.com/Athena-Pro/Curry/pull/4 already applied) into synapse/, since Curry itself isn't a pip-installable package - it's meant to be pointed at via a config path, which only works from a source checkout. Vendoring a single self-contained, stdlib-only file ships it inside NexusOS's own wheel with no extra dependency to reconcile. synapse/curry_store.py opens it into a module-level singleton (curry_db) at import time, the same pattern as memory.store.store and playbooks.store.playbook_store, and main.py imports it so it's genuinely initialized at process startup - preloaded, not lazy-on-first-use. Backed by its own CURRY_DB file (nexus_config.py), separate from memory.db. NexusOS builds exactly one wheel (py3-none-any, no compiled extensions) - there is no separate Windows/macOS/Linux artifact; platform differences are handled by requirement overlays at install time, not by building different wheels. Verified the same wheel actually carries this correctly: built it, confirmed twine check passes, confirmed synapse/curry_core.py and curry_store.py are present in the archive (bin/check.sh's packaging gate now asserts this too), then installed that exact wheel into a throwaway venv and round-tripped a declare_constant/get_constant_latest call against it with no source checkout present - proving "preloaded and ready to be called" holds from the shipped artifact, not just editable-install execution. Android/Termux is unaffected by this change in either direction: it already has a separate, documented, pre-existing blocker in docs/TERMUX.md (no published Android pydantic-core wheel) that has nothing to do with Curry, which is pure stdlib and adds no new native/binary dependency. Scope: preload only, nothing wired into a chat-facing tool yet - no model or user-authored content reaches declare_function/call_function today. Verified: 216 backend tests pass (4 new in test_curry_store.py, including a regression test proving the vendored sandbox fix survived the copy); the 12 pre-existing C/C++/Rust toolchain failures are unrelated and unchanged. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
56 lines
2.4 KiB
Python
56 lines
2.4 KiB
Python
"""synapse/curry_core.py (vendored) + synapse/curry_store.py (NexusOS's preload).
|
|
|
|
Two concerns: the vendor sync didn't silently drop the sandbox fix from
|
|
https://github.com/Athena-Pro/Curry/pull/4, and curry_store actually gives
|
|
NexusOS a live, callable instance without wiring it into any chat-facing tool.
|
|
"""
|
|
import pytest
|
|
|
|
from synapse.curry_core import Curry, TypeSignature
|
|
from synapse import curry_store
|
|
|
|
|
|
def test_curry_store_is_preloaded_and_callable():
|
|
# curry_store.curry_db is a module-level singleton constructed at import
|
|
# time (mirrors synapse.memory.store.store / synapse.playbooks.store.playbook_store)
|
|
# - by the time this test runs, it has already opened its database file.
|
|
assert isinstance(curry_store.curry_db, Curry)
|
|
curry_store.curry_db.declare_constant("t_preload_check", 1, 1, TypeSignature.INT32.value)
|
|
assert curry_store.curry_db.get_constant_latest("t_preload_check")["value"] == 1
|
|
curry_store.curry_db.retire_constant("t_preload_check", 1)
|
|
|
|
|
|
def test_curry_db_path_matches_nexus_config(tmp_path, monkeypatch):
|
|
from synapse import nexus_config
|
|
assert str(curry_store.curry_db.db_path) == str(nexus_config.CURRY_DB)
|
|
|
|
|
|
def test_vendored_sandbox_fix_rejects_format_dunder_escape(tmp_path):
|
|
# Regression test for the vendored fix: a body that hides dunder-attribute
|
|
# traversal inside a str.format() field spec must still be rejected at
|
|
# declare time, not just the literal '.__class__' form. If a future
|
|
# re-vendor from upstream drops the fix, this is what catches it.
|
|
db = Curry(str(tmp_path / "sandbox_check.db"))
|
|
db.declare_function("helper", 1, "1")
|
|
|
|
exploit = "'{0.__globals__}'.format(helper)"
|
|
with pytest.raises(ValueError, match="format"):
|
|
db.declare_function("evil", 1, exploit, function_bindings={"helper": 1})
|
|
|
|
# the original, always-caught dunder-attribute form stays blocked too
|
|
with pytest.raises(ValueError):
|
|
db.declare_function("evil2", 1, "x.__class__", expected_args=["x"])
|
|
|
|
db.close()
|
|
|
|
|
|
def test_vendored_curry_basic_versioning_roundtrip(tmp_path):
|
|
db = Curry(str(tmp_path / "roundtrip.db"))
|
|
db.declare_constant("rate", 1, 0.1, TypeSignature.FLOAT64.value)
|
|
db.declare_function(
|
|
"apply_rate", 1, "amount * (1 + rate)",
|
|
constant_bindings={"rate": 1}, expected_args=["amount"],
|
|
)
|
|
assert db.call_function("apply_rate", 1, {"amount": 100}) == 110.00000000000001
|
|
db.close()
|