mirror of
https://github.com/lancedb/lancedb.git
synced 2026-09-11 07:42:26 +00:00
fix(secrets): admit periods inside Secret names, and rule out the edges
LanceDB namespace names permit periods, so excluding them here put Secrets out of reach inside any namespace a user already has one in -- unreachable to create, alter, describe, drop or bind, with no way to recover but renaming the namespace. A period is ruled out at either end instead, which is RFC 1123's shape and Kubernetes' rule for object names. That stops `.` and `..` and anything reading as a hidden file or a path fragment in a listing or an error. Nothing in the layout depends on it -- the service encodes every segment -- so it buys legibility rather than safety, and it is free only until a name is stored. Names and path segments follow one rule: the two are joined nowhere, but a rule that held for one and not the other would be worse than either. 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
e541a3be93
commit
2f4344e538
@@ -14,7 +14,12 @@ from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
_SECRET_NAME = re.compile(r"^[A-Za-z0-9_-]{1,255}$")
|
||||
# Periods are legal inside a name: excluding them would put Secrets out of reach
|
||||
# of any namespace whose name carries one, which LanceDB namespaces allow. Not
|
||||
# at either end, which is RFC 1123's shape and Kubernetes' rule for object
|
||||
# names: it rules out `.` and `..` and anything that reads as a hidden file or a
|
||||
# path fragment in a listing. Matches the service, which rejects the same shapes.
|
||||
_SECRET_NAME = re.compile(r"^[A-Za-z0-9]([A-Za-z0-9_.-]{0,253}[A-Za-z0-9])?$")
|
||||
_ENV_VARIABLE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
|
||||
|
||||
|
||||
|
||||
@@ -281,6 +281,7 @@ def test_a_credential_value_is_rejected_in_the_binding_position():
|
||||
("openai-prod", "not-a-var", "invalid environment variable name"),
|
||||
("openai-prod", "API-TOKEN", "invalid environment variable name"),
|
||||
("not a name", "API_TOKEN", "invalid Secret name"),
|
||||
("openai$prod", "API_TOKEN", "invalid Secret name"),
|
||||
],
|
||||
)
|
||||
def test_a_binding_validates_both_names_locally(secret, variable, message):
|
||||
@@ -288,6 +289,24 @@ def test_a_binding_validates_both_names_locally(secret, variable, message):
|
||||
EnvVarSecret(secret=secret, env_variable=variable)
|
||||
|
||||
|
||||
def test_a_period_is_legal_inside_a_name_and_not_at_its_edges():
|
||||
"""LanceDB namespaces already permit a period, so a Secret must be nameable
|
||||
alongside them -- inside the name.
|
||||
|
||||
At either end it is ruled out instead, which is RFC 1123's shape and
|
||||
Kubernetes' rule for object names: it stops `.` and `..` and anything that
|
||||
reads as a hidden file or a path fragment in a listing. The service rejects
|
||||
the same shapes, so this is a local answer to the same rule rather than a
|
||||
second one.
|
||||
"""
|
||||
binding = EnvVarSecret(secret="openai.prod.v1", env_variable="OPENAI_API_KEY")
|
||||
assert binding.secret == "openai.prod.v1"
|
||||
|
||||
for name in [".", "..", ".hidden", "trailing.", "-lead", "trail-", "_x"]:
|
||||
with pytest.raises(ValueError, match="invalid Secret name"):
|
||||
EnvVarSecret(secret=name, env_variable="OPENAI_API_KEY")
|
||||
|
||||
|
||||
def _main_udf_source(
|
||||
*, threshold: int = 20, input_annotation: str = "int", comparison: str = ">="
|
||||
) -> str:
|
||||
|
||||
@@ -412,7 +412,7 @@ fn validate_dns_hostname(hostname: &str) -> Result<()> {
|
||||
/// remembering to extend this. Every secrets route is denied, not only the two
|
||||
/// that carry a value: their bodies hold names and page tokens, which are worth
|
||||
/// nothing in a debug log next to the risk of a new verb landing here unnoticed.
|
||||
pub(crate) fn route_carries_credential(path: &str) -> bool {
|
||||
fn route_carries_credential(path: &str) -> bool {
|
||||
path.split('/').any(|segment| segment == "secrets")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user