fix: bootstrap namespace self-ref and write access when created explicitly via --type namespace
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
44
e2e_test.go
44
e2e_test.go
@@ -943,4 +943,48 @@ func TestE2E(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Namespace_ExplicitCreate", func(t *testing.T) {
|
||||||
|
nsDir, err := os.MkdirTemp("", "ax-ns-*")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(nsDir)
|
||||||
|
if err := exec.Command("cp", "./ax", filepath.Join(nsDir, "ax")).Run(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
env := &testEnv{t: t, dir: nsDir, user: "testuser"}
|
||||||
|
env.mustAx("init")
|
||||||
|
|
||||||
|
// Explicitly create a namespace node via --type namespace.
|
||||||
|
nsNode := env.parseNode(env.mustAx("add", "myworkspace", "--type", "namespace", "--json"))
|
||||||
|
|
||||||
|
// The namespace should be in its own namespace (self-reference).
|
||||||
|
if !nsNode.HasRelation("in_namespace", nsNode.ID) {
|
||||||
|
t.Errorf("expected namespace to have in_namespace pointing to itself, got relations: %v", nsNode.Relations)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The creator should have write access to the new namespace.
|
||||||
|
users := env.parseNodes(env.mustAx("list", "--type", "user", "--json"))
|
||||||
|
var userNode *NodeResponse
|
||||||
|
for i := range users {
|
||||||
|
if users[i].Title == "testuser" {
|
||||||
|
userNode = &users[i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if userNode == nil {
|
||||||
|
t.Fatal("could not find testuser node")
|
||||||
|
}
|
||||||
|
if !userNode.HasRelation("has_write_access", nsNode.ID) {
|
||||||
|
t.Errorf("expected creator to have has_write_access to new namespace, got relations: %v", userNode.Relations)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nodes added to the new namespace should be accessible.
|
||||||
|
env.mustAx("add", "task in workspace", "--namespace", "myworkspace", "--json")
|
||||||
|
listed := env.parseNodes(env.mustAx("list", "--namespace", "myworkspace", "--json"))
|
||||||
|
if len(listed) == 0 {
|
||||||
|
t.Error("expected to list nodes in newly created namespace")
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -328,6 +328,30 @@ func (s *nodeServiceImpl) Add(input AddInput) (*models.Node, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Namespace bootstrap: when creating a namespace node directly, apply the
|
||||||
|
// same setup as ensureNamespace — self in_namespace and creator write access.
|
||||||
|
if tmp.GetProperty("type") == "namespace" {
|
||||||
|
if !hasNamespace {
|
||||||
|
// Replace the default namespace rel (user's ns) with self-reference.
|
||||||
|
userNsID, _ := s.resolveIDByNameAndType(st, s.userID, "namespace")
|
||||||
|
if userNsID != "" {
|
||||||
|
if err := st.RemoveRel(id, string(models.RelInNamespace), userNsID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := st.AddRel(id, string(models.RelInNamespace), id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
creatorID, err := s.resolveUserRef(st, s.userID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := st.AddRel(creatorID, string(models.RelHasWriteAccess), id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user