@@ -17,13 +17,15 @@ package usercontext
1717
1818import (
1919 "context"
20+ "encoding/json"
2021 "errors"
2122 "fmt"
2223 "time"
2324
2425 v1 "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1"
2526 "github.com/chainloop-dev/chainloop/app/controlplane/internal/usercontext/entities"
2627 "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz"
28+ "github.com/chainloop-dev/chainloop/app/controlplane/pkg/unmarshal"
2729 "github.com/go-kratos/kratos/v2/log"
2830 "github.com/go-kratos/kratos/v2/middleware"
2931 "github.com/google/uuid"
@@ -68,8 +70,15 @@ func WithCurrentOrganizationMiddleware(userUseCase biz.UserOrgFinder, logger *lo
6870 return nil , fmt .Errorf ("error getting organization name: %w" , err )
6971 }
7072
73+ // Extract organization from resource metadata, takes precedence over header
74+ if orgFromResource , err := getFromResource (req ); err != nil {
75+ return nil , fmt .Errorf ("organization from resource: %w" , err )
76+ } else if orgFromResource != "" {
77+ orgName = orgFromResource
78+ }
79+
7180 if orgName != "" {
72- ctx , err = setCurrentOrganizationFromHeader (ctx , u , orgName , userUseCase )
81+ ctx , err = setCurrentMembershipFromOrgName (ctx , u , orgName , userUseCase )
7382 if err != nil {
7483 return nil , v1 .ErrorUserNotMemberOfOrgErrorNotInOrg ("user is not a member of organization %s" , orgName )
7584 }
@@ -131,7 +140,7 @@ func ResetMembershipsCache() {
131140 membershipsCache .Purge ()
132141}
133142
134- func setCurrentOrganizationFromHeader (ctx context.Context , user * entities.User , orgName string , userUC biz.UserOrgFinder ) (context.Context , error ) {
143+ func setCurrentMembershipFromOrgName (ctx context.Context , user * entities.User , orgName string , userUC biz.UserOrgFinder ) (context.Context , error ) {
135144 membership , err := userUC .MembershipInOrg (ctx , user .ID , orgName )
136145 if err != nil {
137146 return nil , fmt .Errorf ("failed to find membership: %w" , err )
@@ -166,3 +175,72 @@ func setCurrentOrganizationFromDB(ctx context.Context, user *entities.User, user
166175
167176 return ctx , nil
168177}
178+
179+ // Gets organization from resource metadata
180+ // The metadata organization field acts as a namespace for organization resources
181+ func getFromResource (req interface {}) (string , error ) {
182+ if req == nil {
183+ return "" , nil
184+ }
185+
186+ switch v := req .(type ) {
187+ case * v1.WorkflowContractServiceCreateRequest , * v1.WorkflowContractServiceUpdateRequest :
188+ return extractOrg (v )
189+ }
190+
191+ return "" , nil
192+ }
193+
194+ type ResourceBase struct {
195+ Metadata struct {
196+ Organization string `json:"organization"`
197+ } `json:"metadata"`
198+ }
199+
200+ // Extracts organization from request with raw contract data
201+ func extractOrg (req interface {}) (string , error ) {
202+ // Get raw data
203+ rawData , err := getRawData (req )
204+ if err != nil {
205+ return "" , err
206+ }
207+
208+ if len (rawData ) == 0 {
209+ return "" , nil
210+ }
211+
212+ // Identify format
213+ format , err := unmarshal .IdentifyFormat (rawData )
214+ if err != nil {
215+ return "" , err
216+ }
217+
218+ jsonData , err := unmarshal .LoadJSONBytes (rawData , "." + string (format ))
219+ if err != nil {
220+ return "" , err
221+ }
222+
223+ // Unmarshal to extract organization
224+ var resourceBase ResourceBase
225+ if err := json .Unmarshal (jsonData , & resourceBase ); err != nil {
226+ // If unmarshaling fails, return empty string (no error)
227+ // This allows old format schemas to work without the metadata field
228+ return "" , nil
229+ }
230+
231+ return resourceBase .Metadata .Organization , nil
232+ }
233+
234+ type RequestWithRawContract interface {
235+ GetRawContract () []byte
236+ }
237+
238+ // Extracts raw data
239+ func getRawData (req interface {}) ([]byte , error ) {
240+ // Check if the request implements RequestWithRawContract
241+ if rawContractReq , ok := req .(RequestWithRawContract ); ok {
242+ return rawContractReq .GetRawContract (), nil
243+ }
244+
245+ return nil , fmt .Errorf ("request does not have raw contract" )
246+ }
0 commit comments