UAT: local/ namespace allowed with server prefix — violates spec requirement that local/ is reserved for local-only items #3967

Open
opened 2026-04-06 08:00:14 +00:00 by freemo · 0 comments
Owner

Metadata

  • Branch: fix/local-namespace-server-prefix-validation
  • Commit Message: fix(project): reject local/ namespace combined with server prefix in parse_namespaced_name and NamespacedProject
  • Milestone: (backlog — see note below)
  • Parent Epic: #398

Bug Report

Feature Area: Multi-tenant and Isolation Features — Namespace Isolation
Severity: Medium — spec violation in namespace validation; allows semantically contradictory entity names
Found by: UAT tester (ca-uat-tester), feature area: Multi-tenant and Isolation Features


What Was Tested

Namespace isolation enforcement in parse_namespaced_name() and NamespacedProject model validation.

Expected Behavior (from spec)

Per docs/specification.md Glossary > Namespace:

The scoping segment in the name format [[server:]namespace/]name. Defaults to local/ when omitted. local/ is reserved for local-only items. Non-local/ namespaces with server omitted assume the default configured server.

The local/ namespace is explicitly reserved for local-only items. This means:

  1. local/my-project — valid (local-only)
  2. some-server:freemo/my-project — valid (remote, personal namespace)
  3. some-server:local/my-projectINVALID (contradicts spec: local/ cannot be remote)

Actual Behavior

Both parse_namespaced_name() and NamespacedProject allow namespace='local' combined with a server prefix, creating semantically contradictory entities:

# parse_namespaced_name allows this:
result = parse_namespaced_name("some-server:local/my-project")
# result.server = "some-server"
# result.namespace = "local"  
# result.is_local = False  ← CONTRADICTION: local namespace but not local!
# result.is_remote = True   ← CONTRADICTION: local namespace but remote!

# NamespacedProject allows this:
proj = NamespacedProject(name="my-project", namespace="local", server="some-server")
# proj.qualified_name = "some-server:local/my-project"
# proj.is_local = False  ← CONTRADICTION
# proj.is_remote = True  ← CONTRADICTION

Steps to Reproduce

from cleveragents.domain.models.core.project import parse_namespaced_name, NamespacedProject

# Bug 1: parse_namespaced_name
result = parse_namespaced_name("some-server:local/my-project")
print(result.server)     # "some-server"
print(result.namespace)  # "local"
print(result.is_local)   # False — WRONG, should be True or raise ValueError
print(result.is_remote)  # True — WRONG, local/ cannot be remote

# Bug 2: NamespacedProject
proj = NamespacedProject(name="my-project", namespace="local", server="some-server")
print(proj.qualified_name)  # "some-server:local/my-project" — INVALID per spec
print(proj.is_local)        # False — WRONG

Code Locations

  • src/cleveragents/domain/models/core/project.pyparse_namespaced_name() function (line ~120)
  • src/cleveragents/domain/models/core/project.pyNamespacedProject.validate_namespace() validator (line ~290)

Fix Required

Option A (Recommended): Add validation to reject local namespace when a server prefix is present:

In parse_namespaced_name():

if namespace == DEFAULT_NAMESPACE and server is not None:
    raise ValueError(
        f"The 'local/' namespace is reserved for local-only items and "
        f"cannot be combined with a server prefix. "
        f"Use a personal namespace (e.g., '{server}:freemo/name') instead."
    )

In NamespacedProject model validator:

@model_validator(mode="after")
def validate_local_namespace_not_remote(self) -> NamespacedProject:
    if self.namespace == DEFAULT_NAMESPACE and self.server is not None:
        raise ValueError(
            "The 'local/' namespace is reserved for local-only items "
            "and cannot be combined with a server prefix."
        )
    return self

Option B: Treat server:local/name as equivalent to local/name (strip the server prefix when namespace is local).

Impact

  • Allows creation of entities with contradictory is_local=False + namespace='local' state
  • Could cause confusion in server-mode namespace resolution
  • Violates the spec's isolation guarantee that local/ items are strictly local

Subtasks

  • Add validation in parse_namespaced_name() to reject local namespace with server prefix
  • Add model validator in NamespacedProject to reject local namespace with server prefix
  • Add BDD scenarios testing the rejection
  • Run nox (all default sessions), fix any errors
  • Verify coverage >= 97%

Definition of Done

  • parse_namespaced_name("some-server:local/my-project") raises ValueError
  • NamespacedProject(name="x", namespace="local", server="some-server") raises ValidationError
  • BDD scenarios cover the rejection
  • All nox stages pass
  • Coverage >= 97%

Backlog note: This issue was discovered during autonomous operation
on milestone v3.6.0. It does not block milestone completion and has been
placed in the backlog for human review and future milestone assignment.


Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-new-issue-creator

## Metadata - **Branch**: `fix/local-namespace-server-prefix-validation` - **Commit Message**: `fix(project): reject local/ namespace combined with server prefix in parse_namespaced_name and NamespacedProject` - **Milestone**: *(backlog — see note below)* - **Parent Epic**: #398 ## Bug Report **Feature Area:** Multi-tenant and Isolation Features — Namespace Isolation **Severity:** Medium — spec violation in namespace validation; allows semantically contradictory entity names **Found by:** UAT tester (ca-uat-tester), feature area: Multi-tenant and Isolation Features --- ## What Was Tested Namespace isolation enforcement in `parse_namespaced_name()` and `NamespacedProject` model validation. ## Expected Behavior (from spec) Per `docs/specification.md` Glossary > Namespace: > The scoping segment in the name format `[[server:]namespace/]name`. Defaults to `local/` when omitted. **`local/` is reserved for local-only items.** Non-`local/` namespaces with server omitted assume the default configured server. The `local/` namespace is explicitly reserved for local-only items. This means: 1. `local/my-project` — valid (local-only) 2. `some-server:freemo/my-project` — valid (remote, personal namespace) 3. `some-server:local/my-project` — **INVALID** (contradicts spec: `local/` cannot be remote) ## Actual Behavior Both `parse_namespaced_name()` and `NamespacedProject` allow `namespace='local'` combined with a server prefix, creating semantically contradictory entities: ```python # parse_namespaced_name allows this: result = parse_namespaced_name("some-server:local/my-project") # result.server = "some-server" # result.namespace = "local" # result.is_local = False ← CONTRADICTION: local namespace but not local! # result.is_remote = True ← CONTRADICTION: local namespace but remote! # NamespacedProject allows this: proj = NamespacedProject(name="my-project", namespace="local", server="some-server") # proj.qualified_name = "some-server:local/my-project" # proj.is_local = False ← CONTRADICTION # proj.is_remote = True ← CONTRADICTION ``` ## Steps to Reproduce ```python from cleveragents.domain.models.core.project import parse_namespaced_name, NamespacedProject # Bug 1: parse_namespaced_name result = parse_namespaced_name("some-server:local/my-project") print(result.server) # "some-server" print(result.namespace) # "local" print(result.is_local) # False — WRONG, should be True or raise ValueError print(result.is_remote) # True — WRONG, local/ cannot be remote # Bug 2: NamespacedProject proj = NamespacedProject(name="my-project", namespace="local", server="some-server") print(proj.qualified_name) # "some-server:local/my-project" — INVALID per spec print(proj.is_local) # False — WRONG ``` ## Code Locations - `src/cleveragents/domain/models/core/project.py` — `parse_namespaced_name()` function (line ~120) - `src/cleveragents/domain/models/core/project.py` — `NamespacedProject.validate_namespace()` validator (line ~290) ## Fix Required **Option A (Recommended):** Add validation to reject `local` namespace when a server prefix is present: In `parse_namespaced_name()`: ```python if namespace == DEFAULT_NAMESPACE and server is not None: raise ValueError( f"The 'local/' namespace is reserved for local-only items and " f"cannot be combined with a server prefix. " f"Use a personal namespace (e.g., '{server}:freemo/name') instead." ) ``` In `NamespacedProject` model validator: ```python @model_validator(mode="after") def validate_local_namespace_not_remote(self) -> NamespacedProject: if self.namespace == DEFAULT_NAMESPACE and self.server is not None: raise ValueError( "The 'local/' namespace is reserved for local-only items " "and cannot be combined with a server prefix." ) return self ``` **Option B:** Treat `server:local/name` as equivalent to `local/name` (strip the server prefix when namespace is `local`). ## Impact - Allows creation of entities with contradictory `is_local=False` + `namespace='local'` state - Could cause confusion in server-mode namespace resolution - Violates the spec's isolation guarantee that `local/` items are strictly local ## Subtasks - [ ] Add validation in `parse_namespaced_name()` to reject `local` namespace with server prefix - [ ] Add model validator in `NamespacedProject` to reject `local` namespace with server prefix - [ ] Add BDD scenarios testing the rejection - [ ] Run `nox` (all default sessions), fix any errors - [ ] Verify coverage >= 97% ## Definition of Done - [ ] `parse_namespaced_name("some-server:local/my-project")` raises `ValueError` - [ ] `NamespacedProject(name="x", namespace="local", server="some-server")` raises `ValidationError` - [ ] BDD scenarios cover the rejection - [ ] All nox stages pass - [ ] Coverage >= 97% > **Backlog note:** This issue was discovered during autonomous operation > on milestone v3.6.0. It does not block milestone completion and has been > placed in the backlog for human review and future milestone assignment. --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-new-issue-creator
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Blocks
#398 Epic: Post-MVP Resources
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#3967
No description provided.