fix(cli): reject simultaneous workspace variables

This commit is contained in:
Rafid Saad
2026-09-13 14:04:49 -07:00
parent 48051304a9
commit 3a6885d58c
2 changed files with 42 additions and 13 deletions
+13 -6
View File
@@ -1237,6 +1237,17 @@ def _create_host_backend_client(
) -> HostBackendClient:
if env_vars is None:
env_vars = _parse_env_from_config({}, pathlib.Path.cwd() / DEFAULT_CONFIG)
tenant_id = env_vars.get("LANGSMITH_TENANT_ID") or os.environ.get(
"LANGSMITH_TENANT_ID"
)
workspace_id = env_vars.get("LANGSMITH_WORKSPACE_ID") or os.environ.get(
"LANGSMITH_WORKSPACE_ID"
)
if tenant_id and workspace_id:
raise click.UsageError(
"LANGSMITH_TENANT_ID and LANGSMITH_WORKSPACE_ID cannot both be set. "
"Set only one."
)
resolved_api_key = api_key
if not resolved_api_key:
for key_name in _API_KEY_ENV_NAMES:
@@ -1259,13 +1270,9 @@ def _create_host_backend_client(
fg="yellow",
)
resolved_api_key = click.prompt("Enter LangSmith API key", hide_input=True)
tenant_id = (
env_vars.get("LANGSMITH_TENANT_ID")
or os.environ.get("LANGSMITH_TENANT_ID")
or env_vars.get("LANGSMITH_WORKSPACE_ID")
or os.environ.get("LANGSMITH_WORKSPACE_ID")
return HostBackendClient(
host_url, resolved_api_key, tenant_id=tenant_id or workspace_id
)
return HostBackendClient(host_url, resolved_api_key, tenant_id=tenant_id)
def _call_host_backend_with_optional_tenant(
@@ -542,20 +542,18 @@ class TestCreateHostBackendClientNoInput:
@pytest.mark.parametrize("source", ["config", "shell"])
@pytest.mark.parametrize("existing_tenant", [None, "existing-tenant"])
def test_workspace_id_alias(monkeypatch, source, existing_tenant):
@pytest.mark.parametrize("name", ["LANGSMITH_TENANT_ID", "LANGSMITH_WORKSPACE_ID"])
def test_workspace_id_alias(monkeypatch, source, name):
monkeypatch.delenv("LANGSMITH_WORKSPACE_ID", raising=False)
monkeypatch.delenv("LANGSMITH_TENANT_ID", raising=False)
env_vars = {}
if source == "config":
env_vars["LANGSMITH_WORKSPACE_ID"] = "workspace"
env_vars[name] = "workspace"
else:
monkeypatch.setenv("LANGSMITH_WORKSPACE_ID", "workspace")
if existing_tenant:
monkeypatch.setenv("LANGSMITH_TENANT_ID", existing_tenant)
monkeypatch.setenv(name, "workspace")
def handler(request):
assert request.headers["X-Tenant-ID"] == (existing_tenant or "workspace")
assert request.headers["X-Tenant-ID"] == "workspace"
return httpx.Response(200, json={"resources": []})
monkeypatch.setattr(
@@ -570,6 +568,30 @@ def test_workspace_id_alias(monkeypatch, source, existing_tenant):
client._client.close()
@pytest.mark.parametrize("tenant_source", ["config", "shell"])
@pytest.mark.parametrize("workspace_source", ["config", "shell"])
@pytest.mark.parametrize("workspace_id", ["tenant-id", "workspace-id"])
def test_rejects_both_workspace_names(
monkeypatch, tenant_source, workspace_source, workspace_id
):
env_vars = {}
for name, source, value in [
("LANGSMITH_TENANT_ID", tenant_source, "tenant-id"),
("LANGSMITH_WORKSPACE_ID", workspace_source, workspace_id),
]:
monkeypatch.delenv(name, raising=False)
if source == "config":
env_vars[name] = value
else:
monkeypatch.setenv(name, value)
with pytest.raises(
click.UsageError,
match="LANGSMITH_TENANT_ID and LANGSMITH_WORKSPACE_ID cannot both be set",
):
_create_host_backend_client("https://api.example.com", "test-key", env_vars)
def test_workspace_id_is_not_uploaded_as_secret():
assert _secrets_from_env(
{"LANGSMITH_WORKSPACE_ID": "workspace", "APP_SETTING": "value"}