package workspace import ( "fmt" "cloud.o-forge.io/core/oc-lib/dbs" "cloud.o-forge.io/core/oc-lib/models/collaborative_area/shallow_collaborative_area" "cloud.o-forge.io/core/oc-lib/models/peer" "cloud.o-forge.io/core/oc-lib/models/resources" "cloud.o-forge.io/core/oc-lib/models/utils" "cloud.o-forge.io/core/oc-lib/tools" ) // trustedRelations holds peer relations that yield TrustMap = true for a resource. var trustedRelations = map[peer.PeerRelation]bool{ peer.PARTNER: true, peer.MASTER: true, peer.NANO: true, peer.ORGANIZATION_MASTER: true, peer.ORGANIZATION_MEMBER: true, peer.ORGANIZATION_PARTNER: true, } // Workspace is a struct that represents a workspace type Workspace struct { utils.AbstractObject // AbstractObject contains the basic fields of an object (id, name) resources.WorkspaceResourceSet // WorkspaceResourceSet persists both IDs and complete resource objects IsContextual bool `json:"is_contextual" bson:"is_contextual" default:"false"` Active bool `json:"active" bson:"active" default:"false"` Shared string `json:"shared,omitempty" bson:"shared,omitempty"` // Notifications accumulates strings for auto-modifications (e.g. resource removed after peer blacklist). // Cleared by the owner via the notifications update endpoint. Notifications []string `json:"notifications,omitempty" bson:"notifications,omitempty"` // TrustMap maps resource ID → trust bool based on the creator peer's relation. // Not persisted (bson:"-") — recomputed on every load by ComputeTrustAndClean. TrustMap map[string]bool `json:"trust_map,omitempty" bson:"-"` // StaleMap maps resource ID → stale bool. Populated at GET time from the // verify campaign results stored in oc-workspace's stale cache. Not persisted. StaleMap map[string]bool `json:"stale_map,omitempty" bson:"-"` } func (d *Workspace) GetAccessor(request *tools.APIRequest) utils.Accessor { return NewAccessor(request) } func (ao *Workspace) VerifyAuth(callName string, request *tools.APIRequest) bool { if ao.Shared != "" { shared, code, _ := shallow_collaborative_area.NewAccessor(request).LoadOne(ao.Shared) if code != 200 || shared == nil { return false } return shared.VerifyAuth(callName, request) } return ao.AbstractObject.VerifyAuth(callName, request) } // ComputeTrustAndClean populates TrustMap for all resources embedded in this workspace, // removes resources whose creator peer is blacklisted, and appends a deletion notification // for each removal. Returns true when at least one resource was removed (caller should persist). func (w *Workspace) ComputeTrustAndClean() bool { w.TrustMap = map[string]bool{} selfPeer, _ := utils.GetMySelf(peer.NewShallowAccessor()) var selfPeerID string if selfPeer != nil { if p, ok := selfPeer.(*peer.Peer); ok { selfPeerID = p.PeerID } } // Cache peer relations to avoid redundant DB lookups per workspace load. cache := map[string]peer.PeerRelation{} relation := func(creatorID string) peer.PeerRelation { if r, ok := cache[creatorID]; ok { return r } if creatorID == selfPeerID { cache[creatorID] = peer.SELF return peer.SELF } results, _, _ := peer.NewShallowAccessor().Search(&dbs.Filters{ And: map[string][]dbs.Filter{ "peer_id": {{Operator: dbs.EQUAL.String(), Value: creatorID}}, }, }, "", false, 0, 1) rel := peer.NONE if len(results) > 0 { if p, ok := results[0].(*peer.Peer); ok { rel = p.Relation } } cache[creatorID] = rel return rel } setTrust := func(id, creatorID string, rel peer.PeerRelation) { w.TrustMap[id] = (creatorID == selfPeerID) || trustedRelations[rel] } changed := false var keptData []*resources.DataResource for _, r := range w.DataResources { if rel := relation(r.GetCreatorID()); rel == peer.BLACKLIST { w.Notifications = append(w.Notifications, fmt.Sprintf("resource %s (%s) removed: creator peer blacklisted", r.GetName(), r.GetID())) changed = true } else { setTrust(r.GetID(), r.GetCreatorID(), rel) keptData = append(keptData, r) } } w.DataResources = keptData var keptCompute []*resources.ComputeResource for _, r := range w.ComputeResources { if rel := relation(r.GetCreatorID()); rel == peer.BLACKLIST { w.Notifications = append(w.Notifications, fmt.Sprintf("resource %s (%s) removed: creator peer blacklisted", r.GetName(), r.GetID())) changed = true } else { setTrust(r.GetID(), r.GetCreatorID(), rel) keptCompute = append(keptCompute, r) } } w.ComputeResources = keptCompute var keptStorage []*resources.StorageResource for _, r := range w.StorageResources { if rel := relation(r.GetCreatorID()); rel == peer.BLACKLIST { w.Notifications = append(w.Notifications, fmt.Sprintf("resource %s (%s) removed: creator peer blacklisted", r.GetName(), r.GetID())) changed = true } else { setTrust(r.GetID(), r.GetCreatorID(), rel) keptStorage = append(keptStorage, r) } } w.StorageResources = keptStorage var keptProcessing []*resources.ProcessingResource for _, r := range w.ProcessingResources { if rel := relation(r.GetCreatorID()); rel == peer.BLACKLIST { w.Notifications = append(w.Notifications, fmt.Sprintf("resource %s (%s) removed: creator peer blacklisted", r.GetName(), r.GetID())) changed = true } else { setTrust(r.GetID(), r.GetCreatorID(), rel) keptProcessing = append(keptProcessing, r) } } w.ProcessingResources = keptProcessing var keptWorkflow []*resources.WorkflowResource for _, r := range w.WorkflowResources { if rel := relation(r.GetCreatorID()); rel == peer.BLACKLIST { w.Notifications = append(w.Notifications, fmt.Sprintf("resource %s (%s) removed: creator peer blacklisted", r.GetName(), r.GetID())) changed = true } else { setTrust(r.GetID(), r.GetCreatorID(), rel) keptWorkflow = append(keptWorkflow, r) } } w.WorkflowResources = keptWorkflow var keptService []*resources.ServiceResource for _, r := range w.ServiceResources { if rel := relation(r.GetCreatorID()); rel == peer.BLACKLIST { w.Notifications = append(w.Notifications, fmt.Sprintf("resource %s (%s) removed: creator peer blacklisted", r.GetName(), r.GetID())) changed = true } else { setTrust(r.GetID(), r.GetCreatorID(), rel) keptService = append(keptService, r) } } w.ServiceResources = keptService var keptDynamic []*resources.DynamicResource for _, r := range w.DynamicResources { if rel := relation(r.GetCreatorID()); rel == peer.BLACKLIST { w.Notifications = append(w.Notifications, fmt.Sprintf("resource %s (%s) removed: creator peer blacklisted", r.GetName(), r.GetID())) changed = true } else { setTrust(r.GetID(), r.GetCreatorID(), rel) keptDynamic = append(keptDynamic, r) } } w.DynamicResources = keptDynamic var keptNative []*resources.NativeTool for _, r := range w.NativeTools { if rel := relation(r.GetCreatorID()); rel == peer.BLACKLIST { w.Notifications = append(w.Notifications, fmt.Sprintf("resource %s (%s) removed: creator peer blacklisted", r.GetName(), r.GetID())) changed = true } else { setTrust(r.GetID(), r.GetCreatorID(), rel) keptNative = append(keptNative, r) } } w.NativeTools = keptNative return changed }