mirror of
https://github.com/lancedb/lancedb.git
synced 2026-09-11 07:42:26 +00:00
fix(secrets): complete the binding and value contract at the Rust boundary
`validate` checked only the binding count, so a caller reaching the low-level entry point past `bind_secrets` could register an environment variable name the runtime cannot deliver, or bind a Secret to a name `runtime.env` already sets -- which would resolve by delivery order, with a value visible in the Function's record and a value that is not. Secret values are bounded here too, at the limit the service enforces, so an oversized credential is refused before a request body is built rather than after it has been serialized and uploaded. Sandbox-reserved names are deliberately still the service's alone: that list belongs to the runtime that owns it, and a copy here would drift from it silently. Both gate reproducers now fail closed with no request reaching the service. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UfmeJ533rQDnPBkMtjerV6
This commit is contained in:
co-authored by
Claude Opus 5
parent
b85f5f141f
commit
e541a3be93
@@ -179,6 +179,35 @@ def test_a_function_binds_at_most_sixteen_secrets():
|
||||
assert state["requests"] == []
|
||||
|
||||
|
||||
def test_binding_names_are_validated_below_the_python_api():
|
||||
"""The low-level entry point reaches the same validator the typed API does.
|
||||
|
||||
Registration envelopes can be hand-rolled past ``bind_secrets``, so the
|
||||
grammar and the disjointness rule live in Rust, above the backend.
|
||||
"""
|
||||
with _mock_remote_function_catalog() as (host, state):
|
||||
db = lancedb.connect(
|
||||
"db://dev",
|
||||
api_key="fake",
|
||||
host_override=host,
|
||||
client_config={"retry_config": {"retries": 0}},
|
||||
)
|
||||
envelope = json.loads(analyze_caption.registration_request.to_canonical_json())
|
||||
envelope["secret_env_bindings"] = {
|
||||
"BAD=NAME": "openai-prod",
|
||||
"TOKEN_0": "secret-0",
|
||||
}
|
||||
envelope["runtime"]["env"]["TOKEN_0"] = "public"
|
||||
|
||||
async def submit_envelope():
|
||||
return await db._conn._inner.create_function_async(json.dumps(envelope))
|
||||
|
||||
with pytest.raises(ValueError, match="portable"):
|
||||
LOOP.run(submit_envelope())
|
||||
|
||||
assert state["requests"] == []
|
||||
|
||||
|
||||
_SECRET_DEBUG_LOG_SOURCE = """
|
||||
import http.server
|
||||
import json
|
||||
|
||||
Reference in New Issue
Block a user