MCPcopy Index your code
hub / github.com/coder/coder / Filter

Function Filter

coderd/rbac/authz.go:215–280  ·  view source on GitHub ↗

Filter takes in a list of objects, and will filter the list removing all the elements the subject does not have permission for. All objects must be of the same type. Ideally the 'CompileToSQL' is used instead for large sets. This cost scales linearly with the number of objects passed in.

(ctx context.Context, auth Authorizer, subject Subject, action policy.Action, objects []O)

Source from the content-addressed store, hash-verified

213// Ideally the 'CompileToSQL' is used instead for large sets. This cost scales
214// linearly with the number of objects passed in.
215func Filter[O Objecter](ctx context.Context, auth Authorizer, subject Subject, action policy.Action, objects []O) ([]O, error) {
216 if len(objects) == 0 {
217 // Nothing to filter
218 return objects, nil
219 }
220 objectType := objects[0].RBACObject().Type
221 filtered := make([]O, 0)
222
223 // Start the span after the object type is detected. If we are filtering 0
224 // objects, then the span is not interesting. It would just add excessive
225 // 0 time spans that provide no insight.
226 ctx, span := tracing.StartSpan(ctx,
227 rbacTraceAttributes(subject, action, objectType,
228 // For filtering, we are only measuring the total time for the entire
229 // set of objects. This and the 'Prepare' span time
230 // is all that is required to measure the performance of this
231 // function on a per-object basis.
232 attribute.Int("num_objects", len(objects)),
233 ),
234 )
235 defer span.End()
236
237 // Running benchmarks on this function, it is **always** faster to call
238 // auth.Authorize on <10 objects. This is because the overhead of
239 // 'Prepare'. Once we cross 10 objects, then it starts to become
240 // faster
241 if len(objects) < 10 {
242 for _, o := range objects {
243 rbacObj := o.RBACObject()
244 if rbacObj.Type != objectType {
245 return nil, xerrors.Errorf("object types must be uniform across the set (%s), found %s", objectType, rbacObj.Type)
246 }
247 err := auth.Authorize(ctx, subject, action, o.RBACObject())
248 if err == nil {
249 filtered = append(filtered, o)
250 } else if !IsUnauthorizedError(err) {
251 // If the error is not the expected "Unauthorized" error, then
252 // it is something unexpected.
253 return nil, err
254 }
255 }
256 return filtered, nil
257 }
258
259 prepared, err := auth.Prepare(ctx, subject, action, objectType)
260 if err != nil {
261 return nil, xerrors.Errorf("prepare: %w", err)
262 }
263
264 for _, object := range objects {
265 rbacObj := object.RBACObject()
266 if rbacObj.Type != objectType {
267 return nil, xerrors.Errorf("object types must be uniform across the set (%s), found %s", objectType, object.RBACObject().Type)
268 }
269 err := prepared.Authorize(ctx, rbacObj)
270 if err == nil {
271 filtered = append(filtered, object)
272 } else if !IsUnauthorizedError(err) {

Callers 5

AuthorizeFilterFunction · 0.92
BenchmarkRBACFilterFunction · 0.92
fetchWithPostFilterFunction · 0.92
TestFilterErrorFunction · 0.70
TestFilterFunction · 0.70

Calls 8

StartSpanFunction · 0.92
rbacTraceAttributesFunction · 0.85
IntMethod · 0.80
IsUnauthorizedErrorFunction · 0.70
RBACObjectMethod · 0.65
AuthorizeMethod · 0.65
PrepareMethod · 0.65
ErrorfMethod · 0.45

Tested by 3

BenchmarkRBACFilterFunction · 0.74
TestFilterErrorFunction · 0.56
TestFilterFunction · 0.56