4 Commits

Author SHA1 Message Date
eliaskohout 19a8a72674 fix: skip namespace write-permission check when namespace is newly created
Build and Publish Arch Package / build-arch (amd64, x86_64) (push) Successful in 51s
Build and Publish Arch Package / build-arch (arm64, aarch64) (push) Successful in 49s
Build and Publish Docker Image / build-apk (amd64, x86_64) (push) Successful in 47s
Build and Publish Docker Image / build-apk (arm64, aarch64) (push) Successful in 43s
Build and Publish Docker Image / build-and-push-docker (push) Successful in 10m48s
2026-06-12 21:27:47 +02:00
eliaskohout 5f548e134d fix: check write permission on explicit namespace in Add()
Build and Publish Arch Package / build-arch (amd64, x86_64) (push) Successful in 48s
Build and Publish Arch Package / build-arch (arm64, aarch64) (push) Successful in 42s
Build and Publish Docker Image / build-apk (amd64, x86_64) (push) Successful in 44s
Build and Publish Docker Image / build-apk (arm64, aarch64) (push) Successful in 52s
Build and Publish Docker Image / build-and-push-docker (push) Successful in 10m47s
2026-06-12 16:42:37 +02:00
eliaskohout 61c8867742 fix: remove global readability of namespace nodes
Build and Publish Arch Package / build-arch (amd64, x86_64) (push) Successful in 50s
Build and Publish Arch Package / build-arch (arm64, aarch64) (push) Successful in 43s
Build and Publish Docker Image / build-apk (amd64, x86_64) (push) Successful in 44s
Build and Publish Docker Image / build-apk (arm64, aarch64) (push) Successful in 55s
Build and Publish Docker Image / build-and-push-docker (push) Successful in 10m46s
2026-06-12 16:09:51 +02:00
eliaskohout c1f196640b fix: resolve AX_TOKEN before config user in getNodeService
Build and Publish Arch Package / build-arch (amd64, x86_64) (push) Successful in 44s
Build and Publish Arch Package / build-arch (arm64, aarch64) (push) Successful in 49s
Build and Publish Docker Image / build-apk (amd64, x86_64) (push) Successful in 44s
Build and Publish Docker Image / build-apk (arm64, aarch64) (push) Successful in 44s
Build and Publish Docker Image / build-and-push-docker (push) Successful in 10m47s
2026-06-12 15:53:09 +02:00
2 changed files with 37 additions and 12 deletions
+15
View File
@@ -12,6 +12,21 @@ import (
) )
func getNodeService() (service.NodeService, error) { func getNodeService() (service.NodeService, error) {
if token := os.Getenv("AX_TOKEN"); token != "" {
if cfg.Remote.Host != "" {
base := fmt.Sprintf("http://%s:%d", cfg.Remote.Host, cfg.Remote.Port)
return service.NewRemoteNodeService(base, ""), nil
}
st, err := store.FindAndOpenSQLiteStore()
if err != nil {
return nil, err
}
agentID := service.LookupAgentToken(st, token)
if agentID == "" {
return nil, fmt.Errorf("invalid AX_TOKEN: agent not found")
}
return service.NewLocalNodeService(st, agentID), nil
}
user := cfg.User user := cfg.User
if user == "" { if user == "" {
return nil, fmt.Errorf("no user configured: run 'ax user set <username>' first") return nil, fmt.Errorf("no user configured: run 'ax user set <username>' first")
+19 -9
View File
@@ -185,16 +185,15 @@ func (s *nodeServiceImpl) getPermContext() (*permContext, error) {
} }
} }
// User and namespace nodes are globally readable (they represent identities, // User nodes are globally readable (they represent identities,
// and anyone can reference or assign to them). // and anyone can reference or assign to them).
for _, nodeType := range []string{"user", "namespace"} { // Namespace nodes are NOT globally readable; access must be explicitly granted.
nodes, _ := s.store.FindNodes([]*models.Rel{{Type: models.RelType("_type::" + nodeType), Target: ""}}) nodes, _ := s.store.FindNodes([]*models.Rel{{Type: "_type::user", Target: ""}})
for _, n := range nodes { for _, n := range nodes {
if pc.levels[n.ID] < permRead { if pc.levels[n.ID] < permRead {
pc.levels[n.ID] = permRead pc.levels[n.ID] = permRead
} }
} }
}
return pc, nil return pc, nil
} }
@@ -496,10 +495,16 @@ func (s *nodeServiceImpl) Add(input AddInput) (*models.Node, error) {
if nsRef == "" { if nsRef == "" {
nsRef = s.userID nsRef = s.userID
} }
nsID, err := s.resolveNamespaceRef(st, nsRef) nsID, nsCreated, err := s.resolveNamespaceRef(st, nsRef)
if err != nil { if err != nil {
return err return err
} }
// 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 ownerID = nsID
} }
if err := st.AddRel(ownerID, string(models.RelHasOwnership), id); err != nil { if err := st.AddRel(ownerID, string(models.RelHasOwnership), id); err != nil {
@@ -723,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. // Namespace change: transfer ownership from the current namespace to the new one.
if input.Namespace != nil { if input.Namespace != nil {
newNsID, err := s.resolveNamespaceRef(st, *input.Namespace) newNsID, _, err := s.resolveNamespaceRef(st, *input.Namespace)
if err != nil { if err != nil {
return err return err
} }
@@ -971,11 +976,16 @@ func (s *nodeServiceImpl) ensureUser(st store.GraphStore, username string) (stri
return id, nil 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 { 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) { func (s *nodeServiceImpl) ensureNamespace(st store.GraphStore, name string) (string, error) {