Skip to content

Commit 4765761

Browse files
Scope project and allocation reads to membership by default
Fixes #533
1 parent 24cfa3a commit 4765761

30 files changed

Lines changed: 1054 additions & 63 deletions

api/core.openapi.yaml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1991,6 +1991,9 @@ paths:
19911991
- Compute Allocation Usages
19921992
/compute-allocations:
19931993
get:
1994+
description: Callers without the allocations read privilege get only allocations
1995+
where they hold a membership or a governance role on the parent project; filters
1996+
and pagination apply to privileged callers only.
19941997
parameters:
19951998
- description: Filter by project ID
19961999
in: query
@@ -2019,6 +2022,13 @@ paths:
20192022
description: OK
20202023
schema:
20212024
$ref: '#/definitions/ComputeAllocationListResponse'
2025+
"401":
2026+
description: Unauthorized
2027+
schema:
2028+
properties:
2029+
error:
2030+
type: string
2031+
type: object
20222032
security:
20232033
- BearerAuth: []
20242034
summary: List compute allocations (filtered + paginated)
@@ -2055,6 +2065,8 @@ paths:
20552065
- Compute Allocations
20562066
/compute-allocations/{id}:
20572067
get:
2068+
description: Callers without the allocations read privilege must hold a membership
2069+
on the allocation or a governance role on its project; others return 404.
20582070
parameters:
20592071
- description: Compute allocation ID
20602072
in: path
@@ -2068,6 +2080,13 @@ paths:
20682080
description: OK
20692081
schema:
20702082
$ref: '#/definitions/ComputeAllocation'
2083+
"401":
2084+
description: Unauthorized
2085+
schema:
2086+
properties:
2087+
error:
2088+
type: string
2089+
type: object
20712090
"404":
20722091
description: Not Found
20732092
schema:
@@ -2167,6 +2186,8 @@ paths:
21672186
- Compute Allocation Diffs
21682187
/compute-allocations/{id}/memberships:
21692188
get:
2189+
description: Callers without the allocations read privilege must hold a membership
2190+
on the allocation or a governance role on its project; others return 404.
21702191
parameters:
21712192
- description: Compute allocation ID
21722193
in: path
@@ -2182,6 +2203,13 @@ paths:
21822203
items:
21832204
$ref: '#/definitions/AllocationMembershipResponse'
21842205
type: array
2206+
"401":
2207+
description: Unauthorized
2208+
schema:
2209+
properties:
2210+
error:
2211+
type: string
2212+
type: object
21852213
"404":
21862214
description: Not Found
21872215
schema:
@@ -2196,6 +2224,8 @@ paths:
21962224
- Compute Allocation Memberships
21972225
/compute-allocations/{id}/resources:
21982226
get:
2227+
description: Callers without the allocations read privilege must hold a membership
2228+
on the allocation or a governance role on its project; others return 404.
21992229
parameters:
22002230
- description: Compute allocation ID
22012231
in: path
@@ -2211,6 +2241,13 @@ paths:
22112241
items:
22122242
$ref: '#/definitions/ComputeAllocationResourceMapping'
22132243
type: array
2244+
"401":
2245+
description: Unauthorized
2246+
schema:
2247+
properties:
2248+
error:
2249+
type: string
2250+
type: object
22142251
"404":
22152252
description: Not Found
22162253
schema:
@@ -2342,6 +2379,8 @@ paths:
23422379
- Compute Allocation Resources
23432380
/compute-allocations/{id}/usages:
23442381
get:
2382+
description: Callers without the allocations read privilege must hold a membership
2383+
on the allocation or a governance role on its project; others return 404.
23452384
parameters:
23462385
- description: Compute allocation ID
23472386
in: path
@@ -2357,6 +2396,13 @@ paths:
23572396
items:
23582397
$ref: '#/definitions/ComputeAllocationUsage'
23592398
type: array
2399+
"401":
2400+
description: Unauthorized
2401+
schema:
2402+
properties:
2403+
error:
2404+
type: string
2405+
type: object
23602406
"404":
23612407
description: Not Found
23622408
schema:
@@ -2371,6 +2417,8 @@ paths:
23712417
- Compute Allocation Usages
23722418
/compute-allocations/{id}/usages/total:
23732419
get:
2420+
description: Callers without the allocations read privilege must hold a membership
2421+
on the allocation or a governance role on its project; others return 404.
23742422
parameters:
23752423
- description: Compute allocation ID
23762424
in: path
@@ -2384,6 +2432,13 @@ paths:
23842432
description: OK
23852433
schema:
23862434
$ref: '#/definitions/AllocationSUTotalResponse'
2435+
"401":
2436+
description: Unauthorized
2437+
schema:
2438+
properties:
2439+
error:
2440+
type: string
2441+
type: object
23872442
"404":
23882443
description: Not Found
23892444
schema:
@@ -2866,6 +2921,8 @@ paths:
28662921
- Privileges
28672922
/projects:
28682923
get:
2924+
description: Callers without the projects read privilege get only the projects
2925+
they participate in; filters and pagination apply to privileged callers only.
28692926
parameters:
28702927
- description: Filter by PI user ID
28712928
in: query
@@ -2894,6 +2951,13 @@ paths:
28942951
description: OK
28952952
schema:
28962953
$ref: '#/definitions/ProjectListResponse'
2954+
"401":
2955+
description: Unauthorized
2956+
schema:
2957+
properties:
2958+
error:
2959+
type: string
2960+
type: object
28972961
security:
28982962
- BearerAuth: []
28992963
summary: List projects (filtered + paginated, PI joined)
@@ -2930,6 +2994,8 @@ paths:
29302994
- Projects
29312995
/projects/{id}:
29322996
get:
2997+
description: Callers without the projects read privilege only see projects they
2998+
participate in; others return 404.
29332999
parameters:
29343000
- description: Project ID
29353001
in: path
@@ -2943,6 +3009,13 @@ paths:
29433009
description: OK
29443010
schema:
29453011
$ref: '#/definitions/ProjectResponse'
3012+
"401":
3013+
description: Unauthorized
3014+
schema:
3015+
properties:
3016+
error:
3017+
type: string
3018+
type: object
29463019
"404":
29473020
description: Not Found
29483021
schema:

internal/server/allocation.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
"github.com/apache/airavata-custos/internal/store"
2424
"github.com/apache/airavata-custos/pkg/common"
25+
"github.com/apache/airavata-custos/pkg/identity"
2526
"github.com/apache/airavata-custos/pkg/models"
2627
)
2728

@@ -49,11 +50,13 @@ func (s *Server) createComputeAllocation(w http.ResponseWriter, r *http.Request)
4950
}
5051

5152
// @Summary Get a compute allocation by ID
53+
// @Description Callers without the allocations read privilege must hold a membership on the allocation or a governance role on its project; others return 404.
5254
// @Tags Compute Allocations
5355
// @Security BearerAuth
5456
// @Produce json
5557
// @Param id path string true "Compute allocation ID"
5658
// @Success 200 {object} models.ComputeAllocation
59+
// @Failure 401 {object} object{error=string}
5760
// @Failure 404 {object} object{error=string}
5861
// @Router /compute-allocations/{id} [get]
5962
func (s *Server) getComputeAllocation(w http.ResponseWriter, r *http.Request) {
@@ -157,6 +160,7 @@ func (s *Server) getLatestDiffForAllocation(w http.ResponseWriter, r *http.Reque
157160
}
158161

159162
// @Summary List compute allocations (filtered + paginated)
163+
// @Description Callers without the allocations read privilege get only allocations where they hold a membership or a governance role on the parent project; filters and pagination apply to privileged callers only.
160164
// @Tags Compute Allocations
161165
// @Security BearerAuth
162166
// @Produce json
@@ -166,8 +170,25 @@ func (s *Server) getLatestDiffForAllocation(w http.ResponseWriter, r *http.Reque
166170
// @Param limit query integer false "Page size"
167171
// @Param offset query integer false "Page offset"
168172
// @Success 200 {object} ComputeAllocationListResponse
173+
// @Failure 401 {object} object{error=string}
169174
// @Router /compute-allocations [get]
170175
func (s *Server) listComputeAllocations(w http.ResponseWriter, r *http.Request) {
176+
caller := requireCaller(w, r)
177+
if caller == nil {
178+
return
179+
}
180+
if !identity.HasPrivilege(r.Context(), models.AllocationsRead) {
181+
rows, err := s.svc.ListComputeAllocationsForParticipant(r.Context(), caller.UserID)
182+
if err != nil {
183+
common.WriteServiceError(w, err)
184+
return
185+
}
186+
if rows == nil {
187+
rows = []models.ComputeAllocation{}
188+
}
189+
common.WriteJSON(w, http.StatusOK, ComputeAllocationListResponse{Items: rows, Total: len(rows)})
190+
return
191+
}
171192
q := r.URL.Query()
172193
f := store.AllocationListFilter{
173194
ProjectID: q.Get("project_id"),

internal/server/allocation_membership.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,13 @@ func (s *Server) deleteComputeAllocationMembership(w http.ResponseWriter, r *htt
133133
}
134134

135135
// @Summary List members of a compute allocation
136+
// @Description Callers without the allocations read privilege must hold a membership on the allocation or a governance role on its project; others return 404.
136137
// @Tags Compute Allocation Memberships
137138
// @Security BearerAuth
138139
// @Produce json
139140
// @Param id path string true "Compute allocation ID"
140141
// @Success 200 {array} AllocationMembershipResponse
142+
// @Failure 401 {object} object{error=string}
141143
// @Failure 404 {object} object{error=string}
142144
// @Router /compute-allocations/{id}/memberships [get]
143145
func (s *Server) listMembersForAllocation(w http.ResponseWriter, r *http.Request) {

internal/server/allocation_resource.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,13 @@ func (s *Server) detachResourceFromAllocation(w http.ResponseWriter, r *http.Req
181181
}
182182

183183
// @Summary List resources attached to a compute allocation
184+
// @Description Callers without the allocations read privilege must hold a membership on the allocation or a governance role on its project; others return 404.
184185
// @Tags Compute Allocation Resources
185186
// @Security BearerAuth
186187
// @Produce json
187188
// @Param id path string true "Compute allocation ID"
188189
// @Success 200 {array} models.ComputeAllocationResourceMapping
190+
// @Failure 401 {object} object{error=string}
189191
// @Failure 404 {object} object{error=string}
190192
// @Router /compute-allocations/{id}/resources [get]
191193
func (s *Server) listResourcesForAllocation(w http.ResponseWriter, r *http.Request) {

internal/server/allocation_usage.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,13 @@ func (s *Server) deleteComputeAllocationUsage(w http.ResponseWriter, r *http.Req
8080
}
8181

8282
// @Summary List usages for a compute allocation
83+
// @Description Callers without the allocations read privilege must hold a membership on the allocation or a governance role on its project; others return 404.
8384
// @Tags Compute Allocation Usages
8485
// @Security BearerAuth
8586
// @Produce json
8687
// @Param id path string true "Compute allocation ID"
8788
// @Success 200 {array} models.ComputeAllocationUsage
89+
// @Failure 401 {object} object{error=string}
8890
// @Failure 404 {object} object{error=string}
8991
// @Router /compute-allocations/{id}/usages [get]
9092
func (s *Server) listUsagesForAllocation(w http.ResponseWriter, r *http.Request) {
@@ -114,11 +116,13 @@ func (s *Server) listUsagesByUser(w http.ResponseWriter, r *http.Request) {
114116
}
115117

116118
// @Summary Get total SU usage for a compute allocation
119+
// @Description Callers without the allocations read privilege must hold a membership on the allocation or a governance role on its project; others return 404.
117120
// @Tags Compute Allocation Usages
118121
// @Security BearerAuth
119122
// @Produce json
120123
// @Param id path string true "Compute allocation ID"
121124
// @Success 200 {object} AllocationSUTotalResponse
125+
// @Failure 401 {object} object{error=string}
122126
// @Failure 404 {object} object{error=string}
123127
// @Router /compute-allocations/{id}/usages/total [get]
124128
func (s *Server) getTotalSUUsageForAllocation(w http.ResponseWriter, r *http.Request) {

internal/server/integration_common_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ func truncateAll(t *testing.T, database *sqlx.DB) {
8383
"roles",
8484
"user_privileges",
8585
"audit_events",
86+
"compute_allocation_usages",
87+
"compute_allocation_memberships",
88+
"compute_allocation_resource_mappings",
89+
"compute_allocation_resources",
90+
"compute_allocations",
91+
"project_memberships",
92+
"projects",
93+
"compute_cluster_users",
94+
"compute_clusters",
8695
"user_identities",
8796
"users",
8897
"organizations",

0 commit comments

Comments
 (0)