diff --git a/src/service/node_service_impl.go b/src/service/node_service_impl.go index 61884a9..34a4952 100644 --- a/src/service/node_service_impl.go +++ b/src/service/node_service_impl.go @@ -495,11 +495,14 @@ func (s *nodeServiceImpl) Add(input AddInput) (*models.Node, error) { if nsRef == "" { nsRef = s.userID } - nsID, err := s.resolveNamespaceRef(st, nsRef) + nsID, nsCreated, err := s.resolveNamespaceRef(st, nsRef) if err != nil { return err } - if input.Namespace != "" && !pc.canWrite(nsID) { + // Skip the write check when the namespace was just created — the + // current user is the creator/owner, but the permContext was built + // before the namespace existed and therefore doesn't reflect it. + if input.Namespace != "" && !nsCreated && !pc.canWrite(nsID) { return fmt.Errorf("permission denied: no write access to namespace %q", input.Namespace) } ownerID = nsID @@ -725,7 +728,7 @@ func (s *nodeServiceImpl) Update(id string, input UpdateInput) (*models.Node, er // Namespace change: transfer ownership from the current namespace to the new one. if input.Namespace != nil { - newNsID, err := s.resolveNamespaceRef(st, *input.Namespace) + newNsID, _, err := s.resolveNamespaceRef(st, *input.Namespace) if err != nil { return err } @@ -973,11 +976,16 @@ func (s *nodeServiceImpl) ensureUser(st store.GraphStore, username string) (stri return id, nil } -func (s *nodeServiceImpl) resolveNamespaceRef(st store.GraphStore, ref string) (string, error) { +// resolveNamespaceRef returns the namespace ID and whether it was newly created. +func (s *nodeServiceImpl) resolveNamespaceRef(st store.GraphStore, ref string) (string, bool, error) { if exists, _ := st.NodeExists(ref); exists { - return ref, nil + return ref, false, nil } - return s.ensureNamespace(st, ref) + id, err := s.ensureNamespace(st, ref) + if err != nil { + return "", false, err + } + return id, true, nil } func (s *nodeServiceImpl) ensureNamespace(st store.GraphStore, name string) (string, error) {