Add namespaces support (CRUD, RBAC, namespace-scoped users)#169
Add namespaces support (CRUD, RBAC, namespace-scoped users)#169jfrancoa wants to merge 10 commits into
Conversation
There was a problem hiding this comment.
Orca Security Scan Summary
| Status | Check | Issues by priority | |
|---|---|---|---|
| Infrastructure as Code | View in Orca | ||
| SAST | View in Orca | ||
| Secrets | View in Orca | ||
| Vulnerabilities | View in Orca |
There was a problem hiding this comment.
Pull request overview
This PR adds end-to-end CLI support for Weaviate “namespaces” (CRUD commands, RBAC permission parsing/rendering, and namespace-scoped DB user creation/output), plus accompanying unit tests and docs updates.
Changes:
- Introduces
NamespaceManagerand new CLI commands:create/get/delete namespace(with--jsonsupport). - Extends RBAC permission parsing/output to support
manage_namespaces:<name>[,<name>...]and rendersnamespaces_permissionsin role output. - Adds optional
--namespacetocreate userand surfaces the namespace inget useroutputs (text + JSON), with unit tests.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| weaviate_cli/utils.py | Adds manage_namespaces permission parsing + _create_permission support for namespaces. |
| weaviate_cli/managers/user_manager.py | Adds namespace forwarding on user creation; prints namespace in user outputs. |
| weaviate_cli/managers/role_manager.py | Renders namespaces_permissions in role JSON/text output. |
| weaviate_cli/managers/namespace_manager.py | New manager implementing namespace CRUD and printing. |
| weaviate_cli/defaults.py | Adds defaults dataclasses for namespace commands and create-user namespace default. |
| weaviate_cli/commands/get.py | Adds get namespace subcommand; includes namespace in get user --all JSON. |
| weaviate_cli/commands/delete.py | Adds delete namespace subcommand. |
| weaviate_cli/commands/create.py | Adds create namespace subcommand; adds --namespace to create user. |
| test/unittests/test_utils.py | Adds unit tests for manage_namespaces parsing + wildcard rejection. |
| test/unittests/test_managers/test_user_manager.py | Adds tests for namespace kwarg forwarding and namespace rendering. |
| test/unittests/test_managers/test_namespace_manager.py | New unit tests for NamespaceManager CRUD + output modes. |
| requirements-dev.txt | Temporarily pins weaviate-client to a Git branch for namespaces support. |
| .claude/skills/operating-weaviate-cli/SKILL.md | Documents namespace commands, namespace-scoped users, and RBAC permission usage. |
| .claude/skills/operating-weaviate-cli/references/rbac.md | Documents manage_namespaces permission. |
| .claude/skills/operating-weaviate-cli/references/namespaces.md | New reference page for namespaces feature. |
| .claude/skills/contributing-to-weaviate-cli/SKILL.md | Updates contributor docs to include namespace commands/manager module. |
| .claude/skills/contributing-to-weaviate-cli/references/architecture.md | Adds namespace_manager.py to the manager list. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@copilot review |
Addressed the two remaining unresolved review comments in commits
All 324 unit tests pass and lint is clean. |
Adds end-to-end CLI surface for the Weaviate namespaces feature (server >= 1.38.0, python-client jose/namespaces branch): - create/get/delete namespace subcommands backed by NamespaceManager - manage_namespaces:<name>[,<name>...] permission parsing, with the bare wildcard form rejected so every grant names an explicit namespace - --namespace flag on create user; create user JSON/text and get user output surface the namespace; create_user only forwards the kwarg when set so the CLI keeps working against non-namespaced clusters - get role text/JSON now renders namespaces_permissions - requirements-dev.txt temporarily points at the python-client jose/namespaces branch until that release ships Closes #168 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Reject empty namespace names in manage_namespaces permission parsing (manage_namespaces: or ns1,,ns2) - Add unit tests for empty namespace name edge cases - Fix namespace naming rule docs: underscores are not allowed per RFC ([a-z][a-z0-9]*) - Update all doc examples to use valid namespace names (tenantswest, tenantseast, tenantssouth) - Pin weaviate-client to git branch in setup.cfg so CI installs namespace-enabled client Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Agent-Logs-Url: https://github.com/weaviate/weaviate-cli/sessions/885f6e27-f122-407c-8e0b-e5228dacd9fc Co-authored-by: jfrancoa <23482278+jfrancoa@users.noreply.github.com>
Agent-Logs-Url: https://github.com/weaviate/weaviate-cli/sessions/885f6e27-f122-407c-8e0b-e5228dacd9fc Co-authored-by: jfrancoa <23482278+jfrancoa@users.noreply.github.com>
Several methods of the weaviate-python-client are not the usual
"raise on failure" style. Instead they accept multiple HTTP status
codes as "ok" and return:
* bool -- False means a logical no-op (404 not found,
409 already in target state, ...)
* Optional[X] -- None means "not found" (404)
The CLI was discarding those returns and silently reporting success
on no-ops -- e.g. `delete user --user_name=ghost` printed
"User 'ghost' deleted successfully." with exit code 0.
Surface the no-op as a clear error in the affected managers:
* UserManager
- delete_user : raise on False (404)
- update_user : raise on False from activate()/deactivate()
(409 already in target state)
- get_user : raise on None (404) when looking up by name
* AliasManager
- delete_alias : raise on False (404)
- update_alias : raise on False (404)
- get_alias : fix return type hint to Optional[AliasReturn]
* DataManager
- __delete_data : raise on False from data.delete_by_id()
(404) in the uuid path
The CLI commands already wrap manager calls in `try/except Exception`
and exit 1 with `Error: ...`, so no command-layer changes were needed
beyond simplifying delete_user_cli (already on this branch).
Add regression coverage on two layers:
* Manager unit tests for each new bool=False / None path
(test_user_manager.py, test_alias_manager.py, test_data_manager.py)
* End-to-end CliRunner tests in
test/unittests/test_cli_bool_contract.py that pin the contract:
a no-op exits non-zero with a clear message and never prints a
success line. If a future contributor swallows a bool again,
these tests fail loudly.
Co-authored-by: Cursor <cursoragent@cursor.com>
`weaviate-cli get user --user_name X` calls `users.db.get(user_id=X)`, which returns None for any user that isn't a DB user. The previous "User 'X' not found." surfaced that None cleanly but was misleading for OIDC users: the user does exist, just not in the DB store, and the Weaviate Python client has no `users.oidc.get(...)` to fetch them with. Expand the not-found message to name the DB store explicitly and point at `get role --user_name X --user_type oidc`, which *can* surface OIDC user info (assigned roles). No new CLI flags — adding `--user_type oidc` to `get user` would be a dead end since the client can't act on it. Update unit + CLI bool-contract tests to lock in the new wording. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
On namespace-enabled clusters (Weaviate 1.38+), `client.collections.list_all()`
returns keys differently depending on the credential type:
* namespace-scoped DB user — short names ("Movies"), namespace is implicit
* global/operator credential — qualified names ("ns:Movies")
The previous `get collection` flow assumed short names everywhere: it
passed each list_all() key straight to `collections.get(...)`, which 404s
under operator credentials, and lacked any way to target a single namespace
or a qualified collection.
Add two options to `get collection`:
* --namespace <name>
- with --collection NAME : resolves the API target to NAMESPACE:NAME
(or leaves it as-is if NAME already contains ":")
- without --collection : filters the listing to that namespace
* --list-qualified-keys
- listing-only flag; passes each list_all() key verbatim to the API.
Equivalent to `--namespace '*'` but avoids the shell-glob footgun
of an unquoted `*`. Mutually exclusive with --namespace <name>.
Default behavior (no flags) is unchanged for namespace-scoped users: the
manager continues to strip the `namespace:` prefix when fetching each
collection's details. When that strip yields a 404 against operator
credentials, raise a hint pointing at `--list-qualified-keys` /
`--namespace <ns>` and enumerate the namespaces seen in list_all().
Apply the same prefix-stripping fix to ShardManager.get_shards /
update_shards (`--all` paths) and CollectionManager.delete_collection
(`--all`) so they keep working on namespace-scoped users.
Cover the new paths with 12 manager-level tests and document the operator
vs namespace-scoped distinction in the operating skill (SKILL.md,
references/collections.md, references/namespaces.md).
Co-Authored-By: Cursor <cursoragent@cursor.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`DataManager._query_data` was passing `return_objects=True` to
`collection.query.bm25(...)`, but the weaviate-python-client's
`_BM25QueryExecutor.bm25` has no such parameter — its signature is
`query, return_metadata, return_properties, limit, ...`. Any keyword
call (`weaviate-cli query data --search_type keyword`) raised:
TypeError: _BM25QueryExecutor.bm25() got an unexpected keyword
argument 'return_objects'
The argument was a stray addition from commit 83a7189 and isn't needed:
bm25 returns objects by default, just like the sibling `fetch_objects`,
`near_text` and `hybrid` calls in the same method.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brings weaviate-cli to parity with weaviate-python-client PR #2033
(commit c4afc9f3), which added an optional home_node on namespace
create, a read-only state field, and a new PUT /namespaces/{name}
endpoint:
- create namespace gains optional --home_node (forwarded only when set,
so older namespace-aware clusters are unaffected)
- new `update namespace --name --home_node` command backed by
client.namespaces.update (home_node is the only mutable field)
- get namespace surfaces home_node and read-only state in text and JSON,
via a shared NamespaceManager.namespace_to_dict() helper; both keys are
omitted when the server does not return them
- bump requirements-dev.txt client pin to c4afc9f3 so the new flags are
backed by the client
- unit + CLI wiring tests for the new fields and command
- operating skill docs updated (SKILL.md + references/namespaces.md)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The server no longer accepts a separate namespace field when creating a DB user; the namespace is derived from a namespace-qualified id "<namespace>:<user>" in the URL path (weaviate-python-client commit 26fe203e). Bring the CLI to parity: - create user: remove the --namespace option and the namespace-conditional output branches. Bind a user to a namespace by passing a qualified --user_name "<namespace>:<user>", forwarded verbatim to users.db.create(user_id=...). Update the --user_name help text. - UserManager.create_user: drop the namespace parameter; always call users.db.create(user_id=user_name). get/print of users still surfaces the namespace the server returns for global operators (unchanged). - defaults: remove CreateUserDefaults.namespace. - requirements-dev.txt: bump client pin to 26fe203e (drops the namespace arg). Tests: replace the namespace-kwarg manager tests with a qualified-id forwarding test; add CLI tests that the qualified --user_name reaches the manager and that the dropped --namespace flag is now a usage error. Docs (SKILL.md, namespaces.md) updated to the qualified-id form. 397 unit tests pass, lint clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
End-to-end CLI surface for the Weaviate namespaces feature (server >= 1.38.0, paired with weaviate-python-client PR #2033 / branch
jose/namespaces):create namespace --name <ns>,get namespace --name <ns> | --all,delete namespace --name <ns>. All commands support--json. Backed by a newNamespaceManager.manage_namespaces:<name>[,<name>...]parses throughparse_permission→Permissions.namespaces(...). The baremanage_namespaceswildcard is rejected so every grant names an explicit namespace.get role(text and JSON) now rendersnamespaces_permissions.create user --user_name <u> --namespace <ns>forwards the newnamespacekwarg.UserManager.create_useronly sends the kwarg when set, so the CLI keeps working against non-namespaced clusters and older clients.get usertext and JSON output (single user and--all) surface the namespace when present.operating-weaviate-cligains a Namespaces section +references/namespaces.md;references/rbac.mddocumentsmanage_namespaces.contributing-to-weaviate-clilists the newnamespace_manager.pymodule.Tests
test/unittests/test_managers/test_namespace_manager.py(15 tests) — happy paths, errors, JSON output, missing-name validation.parse_permissioncases for single namespace, multi-namespace, and wildcard rejection intest_utils.py.create_usertests covering namespace forwarding (and the absence of the kwarg when not provided), plusprint_db_usernamespace rendering tests.make test→ 323 passed (was 308).make lintpasses.Note on requirements-dev.txt
weaviate-clientis temporarily pinned to thejose/namespacesbranch of the python client so the newweaviate.namespacesmodule resolves and CI can run. Revert to a normal version pin (weaviate-client>=4.21.xor whatever ships) once weaviate-python-client #2033 merges and a release is cut.Test plan
make lintpassesmake testpassesweaviate-cli create namespace --name demo_ns --jsonagainst a Weaviate 1.38.0+ clusterweaviate-cli create user --user_name u1 --namespace demo_ns --jsonweaviate-cli create role --role_name r1 -p manage_namespaces:demo_ns --jsonandweaviate-cli get role --role_name r1 --jsonCloses #168
🤖 Generated with Claude Code