[arvados] created: 2.7.0-6627-g55009aa6c2

git repository hosting git at public.arvados.org
Thu May 30 15:23:49 UTC 2024


        at  55009aa6c287dc7ef98e68d2225a3469a601c674 (commit)


commit 55009aa6c287dc7ef98e68d2225a3469a601c674
Author: Tom Clegg <tom at curii.com>
Date:   Thu May 30 11:23:16 2024 -0400

    20640: Add computed permissions API.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at curii.com>

diff --git a/lib/controller/federation/conn.go b/lib/controller/federation/conn.go
index c2cbfec008..51f7a21c7d 100644
--- a/lib/controller/federation/conn.go
+++ b/lib/controller/federation/conn.go
@@ -408,6 +408,10 @@ func (conn *Conn) CollectionUntrash(ctx context.Context, options arvados.Untrash
 	return conn.chooseBackend(options.UUID).CollectionUntrash(ctx, options)
 }
 
+func (conn *Conn) ComputedPermissionList(ctx context.Context, options arvados.ListOptions) (arvados.ComputedPermissionList, error) {
+	return conn.local.ComputedPermissionList(ctx, options)
+}
+
 func (conn *Conn) ContainerList(ctx context.Context, options arvados.ListOptions) (arvados.ContainerList, error) {
 	return conn.generated_ContainerList(ctx, options)
 }
diff --git a/lib/controller/router/router.go b/lib/controller/router/router.go
index 39c7d871d8..b3c7b115ff 100644
--- a/lib/controller/router/router.go
+++ b/lib/controller/router/router.go
@@ -184,6 +184,13 @@ func (rtr *router) addRoutes() {
 				return rtr.backend.CollectionUntrash(ctx, *opts.(*arvados.UntrashOptions))
 			},
 		},
+		{
+			arvados.EndpointComputedPermissionList,
+			func() interface{} { return &arvados.ListOptions{} },
+			func(ctx context.Context, opts interface{}) (interface{}, error) {
+				return rtr.backend.ComputedPermissionList(ctx, *opts.(*arvados.ListOptions))
+			},
+		},
 		{
 			arvados.EndpointContainerCreate,
 			func() interface{} { return &arvados.CreateOptions{} },
diff --git a/lib/controller/rpc/conn.go b/lib/controller/rpc/conn.go
index 3125ae29be..899c5ce7de 100644
--- a/lib/controller/rpc/conn.go
+++ b/lib/controller/rpc/conn.go
@@ -341,6 +341,13 @@ func (conn *Conn) CollectionUntrash(ctx context.Context, options arvados.Untrash
 	return resp, err
 }
 
+func (conn *Conn) ComputedPermissionList(ctx context.Context, options arvados.ListOptions) (arvados.ComputedPermissionList, error) {
+	ep := arvados.EndpointComputedPermissionList
+	var resp arvados.ComputedPermissionList
+	err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
+	return resp, err
+}
+
 func (conn *Conn) ContainerCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Container, error) {
 	ep := arvados.EndpointContainerCreate
 	var resp arvados.Container
diff --git a/sdk/go/arvados/api.go b/sdk/go/arvados/api.go
index d2e2b2088c..2c932531ae 100644
--- a/sdk/go/arvados/api.go
+++ b/sdk/go/arvados/api.go
@@ -42,6 +42,7 @@ var (
 	EndpointCollectionDelete                = APIEndpoint{"DELETE", "arvados/v1/collections/{uuid}", ""}
 	EndpointCollectionTrash                 = APIEndpoint{"POST", "arvados/v1/collections/{uuid}/trash", ""}
 	EndpointCollectionUntrash               = APIEndpoint{"POST", "arvados/v1/collections/{uuid}/untrash", ""}
+	EndpointComputedPermissionList          = APIEndpoint{"GET", "arvados/v1/computed_permissions", ""}
 	EndpointContainerCreate                 = APIEndpoint{"POST", "arvados/v1/containers", "container"}
 	EndpointContainerUpdate                 = APIEndpoint{"PATCH", "arvados/v1/containers/{uuid}", "container"}
 	EndpointContainerPriorityUpdate         = APIEndpoint{"POST", "arvados/v1/containers/{uuid}/update_priority", "container"}
@@ -291,6 +292,7 @@ type API interface {
 	CollectionDelete(ctx context.Context, options DeleteOptions) (Collection, error)
 	CollectionTrash(ctx context.Context, options DeleteOptions) (Collection, error)
 	CollectionUntrash(ctx context.Context, options UntrashOptions) (Collection, error)
+	ComputedPermissionList(ctx context.Context, options ListOptions) (ComputedPermissionList, error)
 	ContainerCreate(ctx context.Context, options CreateOptions) (Container, error)
 	ContainerUpdate(ctx context.Context, options UpdateOptions) (Container, error)
 	ContainerPriorityUpdate(ctx context.Context, options UpdateOptions) (Container, error)
diff --git a/sdk/go/arvados/link.go b/sdk/go/arvados/link.go
index 7df6b84d60..3bf5bcb8dd 100644
--- a/sdk/go/arvados/link.go
+++ b/sdk/go/arvados/link.go
@@ -32,3 +32,15 @@ type LinkList struct {
 	Offset         int    `json:"offset"`
 	Limit          int    `json:"limit"`
 }
+
+type ComputedPermission struct {
+	UserUUID   string `json:"user_uuid"`
+	TargetUUID string `json:"target_uuid"`
+	PermLevel  string `json:"perm_level"`
+}
+
+type ComputedPermissionList struct {
+	Items          []ComputedPermission `json:"items"`
+	ItemsAvailable int                  `json:"items_available"`
+	Limit          int                  `json:"limit"`
+}
diff --git a/sdk/go/arvadostest/api.go b/sdk/go/arvadostest/api.go
index 658874c6d7..5da69eb22c 100644
--- a/sdk/go/arvadostest/api.go
+++ b/sdk/go/arvadostest/api.go
@@ -108,6 +108,10 @@ func (as *APIStub) CollectionUntrash(ctx context.Context, options arvados.Untras
 	as.appendCall(ctx, as.CollectionUntrash, options)
 	return arvados.Collection{}, as.Error
 }
+func (as *APIStub) ComputedPermissionList(ctx context.Context, options arvados.ListOptions) (arvados.ComputedPermissionList, error) {
+	as.appendCall(ctx, as.ComputedPermissionList, options)
+	return arvados.ComputedPermissionList{}, as.Error
+}
 func (as *APIStub) ContainerCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Container, error) {
 	as.appendCall(ctx, as.ContainerCreate, options)
 	return arvados.Container{}, as.Error
diff --git a/sdk/python/arvados-v1-discovery.json b/sdk/python/arvados-v1-discovery.json
index 0dcec6bb20..2c9d1a73f6 100644
--- a/sdk/python/arvados-v1-discovery.json
+++ b/sdk/python/arvados-v1-discovery.json
@@ -1539,6 +1539,70 @@
         }
       }
     },
+    "computed_permissions": {
+      "methods": {
+        "list": {
+          "id": "arvados.computed_permissions.list",
+          "path": "computed_permissions",
+          "httpMethod": "GET",
+          "description": "List ComputedPermissions.\n\n                   The <code>list</code> method returns a\n                   <a href=\"/api/resources.html\">resource list</a> of\n                   matching ComputedPermissions. For example:\n\n                   <pre>\n                   {\n                    \"kind\":\"arvados#computedPermissionList\",\n                    \"etag\":\"\",\n                    \"self_link\":\"\",\n                    \"next_page_token\":\"\",\n                    \"next_link\":\"\",\n                    \"items\":[\n                       ...\n                    ],\n                    \"items_available\":745,\n                    \"_profile\":{\n                     \"request_time\":0.157236317\n                    }\n                    </pre>",
+          "parameters": {
+            "filters": {
+              "type": "array",
+              "required": false,
+              "description": "",
+              "location": "query"
+            },
+            "where": {
+              "type": "object",
+              "required": false,
+              "description": "",
+              "location": "query"
+            },
+            "order": {
+              "type": "array",
+              "required": false,
+              "description": "",
+              "location": "query"
+            },
+            "select": {
+              "type": "array",
+              "description": "Attributes of each object to return in the response.",
+              "required": false,
+              "location": "query"
+            },
+            "distinct": {
+              "type": "boolean",
+              "required": false,
+              "default": "false",
+              "description": "",
+              "location": "query"
+            },
+            "limit": {
+              "type": "integer",
+              "required": false,
+              "default": "100",
+              "description": "",
+              "location": "query"
+            },
+            "count": {
+              "type": "string",
+              "required": false,
+              "default": "exact",
+              "description": "",
+              "location": "query"
+            }
+          },
+          "response": {
+            "$ref": "ComputedPermissionList"
+          },
+          "scopes": [
+            "https://api.arvados.org/auth/arvados",
+            "https://api.arvados.org/auth/arvados.readonly"
+          ]
+        }
+      }
+    },
     "containers": {
       "methods": {
         "get": {
@@ -5919,6 +5983,57 @@
         }
       }
     },
+    "ComputedPermissionList": {
+      "id": "ComputedPermissionList",
+      "description": "ComputedPermission list",
+      "type": "object",
+      "properties": {
+        "kind": {
+          "type": "string",
+          "description": "Object type. Always arvados#computedPermissionList.",
+          "default": "arvados#computedPermissionList"
+        },
+        "etag": {
+          "type": "string",
+          "description": "List version."
+        },
+        "items": {
+          "type": "array",
+          "description": "The list of ComputedPermissions.",
+          "items": {
+            "$ref": "ComputedPermission"
+          }
+        },
+        "next_link": {
+          "type": "string",
+          "description": "A link to the next page of ComputedPermissions."
+        },
+        "next_page_token": {
+          "type": "string",
+          "description": "The page token for the next page of ComputedPermissions."
+        },
+        "selfLink": {
+          "type": "string",
+          "description": "A link back to this list."
+        }
+      }
+    },
+    "ComputedPermission": {
+      "id": "ComputedPermission",
+      "description": "ComputedPermission",
+      "type": "object",
+      "properties": {
+        "user_uuid": {
+          "type": "string"
+        },
+        "target_uuid": {
+          "type": "string"
+        },
+        "perm_level": {
+          "type": "integer"
+        }
+      }
+    },
     "ContainerList": {
       "id": "ContainerList",
       "description": "Container list",
diff --git a/sdk/python/tests/test_computed_permissions.py b/sdk/python/tests/test_computed_permissions.py
new file mode 100644
index 0000000000..7f0eee2014
--- /dev/null
+++ b/sdk/python/tests/test_computed_permissions.py
@@ -0,0 +1,18 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import arvados
+from . import run_test_server
+
+class ComputedPermissionTest(run_test_server.TestCaseWithServers):
+    def test_computed_permission(self):
+        run_test_server.authorize_with('admin')
+        api_client = arvados.api('v1')
+        active_user_uuid = run_test_server.fixture('users')['active']['uuid']
+        resp = api_client.computed_permissions().list(
+            filters=[['user_uuid', '=', active_user_uuid]],
+        ).execute()
+        assert len(resp['items']) > 0
+        for item in resp['items']:
+            assert item['user_uuid'] == active_user_uuid
diff --git a/services/api/app/controllers/arvados/v1/computed_permissions_controller.rb b/services/api/app/controllers/arvados/v1/computed_permissions_controller.rb
new file mode 100644
index 0000000000..9291a37ba6
--- /dev/null
+++ b/services/api/app/controllers/arvados/v1/computed_permissions_controller.rb
@@ -0,0 +1,7 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
+class Arvados::V1::ComputedPermissionsController < ApplicationController
+  before_action :admin_required
+end
diff --git a/services/api/app/controllers/arvados/v1/schema_controller.rb b/services/api/app/controllers/arvados/v1/schema_controller.rb
index dd7a7a759e..0c50db2b64 100644
--- a/services/api/app/controllers/arvados/v1/schema_controller.rb
+++ b/services/api/app/controllers/arvados/v1/schema_controller.rb
@@ -397,6 +397,19 @@ class Arvados::V1::SchemaController < ApplicationController
       end
     end
 
+    # The computed_permissions controller does not offer all of the
+    # usual methods and attributes.  Modify discovery doc accordingly.
+    discovery[:resources]['computed_permissions'][:methods].select! do |method|
+      method == :list
+    end
+    discovery[:resources]['computed_permissions'][:methods][:list][:parameters].select! do |param|
+      ![:cluster_id, :bypass_federation, :offset].include?(param)
+    end
+    discovery[:schemas]['ComputedPermission'].delete(:uuidPrefix)
+    discovery[:schemas]['ComputedPermission'][:properties].select! do |prop|
+      ![:uuid, :etag].include?(prop)
+    end
+
     # The 'replace_files' option is implemented in lib/controller,
     # not Rails -- we just need to add it here so discovery-aware
     # clients know how to validate it.
diff --git a/services/api/app/models/arvados_model.rb b/services/api/app/models/arvados_model.rb
index 9ee2cca410..8316a30a4e 100644
--- a/services/api/app/models/arvados_model.rb
+++ b/services/api/app/models/arvados_model.rb
@@ -170,10 +170,6 @@ class ArvadosModel < ApplicationRecord
     end.map(&:name)
   end
 
-  def self.attribute_column attr
-    self.columns.select { |col| col.name == attr.to_s }.first
-  end
-
   def self.attributes_required_columns
     # This method returns a hash.  Each key is the name of an API attribute,
     # and it's mapped to a list of database columns that must be fetched
@@ -564,18 +560,6 @@ class ArvadosModel < ApplicationRecord
     "to_tsvector('english', substr(#{parts.join(" || ' ' || ")}, 0, 8000))"
   end
 
-  def self.apply_filters query, filters
-    ft = record_filters filters, self
-    if not ft[:cond_out].any?
-      return query
-    end
-    ft[:joins].each do |t|
-      query = query.joins(t)
-    end
-    query.where('(' + ft[:cond_out].join(') AND (') + ')',
-                          *ft[:param_out])
-  end
-
   @_add_uuid_to_name = false
   def add_uuid_to_make_unique_name
     @_add_uuid_to_name = true
diff --git a/services/api/app/models/computed_permission.rb b/services/api/app/models/computed_permission.rb
new file mode 100644
index 0000000000..af89eadf1f
--- /dev/null
+++ b/services/api/app/models/computed_permission.rb
@@ -0,0 +1,58 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
+require 'record_filters'
+
+class ComputedPermission < ApplicationRecord
+  self.table_name = 'materialized_permissions'
+  include CurrentApiClient
+  include CommonApiTemplate
+  extend RecordFilters
+
+  PERM_LEVEL_S = ['none', 'can_read', 'can_write', 'can_manage']
+
+  api_accessible :user do |t|
+    t.add :user_uuid
+    t.add :target_uuid
+    t.add :perm_level_s, as: :perm_level
+  end
+
+  protected
+
+  def perm_level_s
+    PERM_LEVEL_S[perm_level]
+  end
+
+  def self.default_orders
+    ["#{table_name}.user_uuid", "#{table_name}.target_uuid"]
+  end
+
+  def self.readable_by(*args)
+    self
+  end
+
+  def self.searchable_columns(operator)
+    if !operator.match(/[<=>]/) && !operator.in?(['in', 'not in'])
+      []
+    else
+      ['user_uuid', 'target_uuid']
+    end
+  end
+
+  def self.limit_index_columns_read
+    []
+  end
+
+  def self.selectable_attributes
+    %w(user_uuid target_uuid perm_level)
+  end
+
+  def self.columns_for_attributes(select_attributes)
+    select_attributes
+  end
+
+  def self.serialized_attributes
+    {}
+  end
+end
diff --git a/services/api/app/models/group.rb b/services/api/app/models/group.rb
index d4c81fe9d1..d159b73c94 100644
--- a/services/api/app/models/group.rb
+++ b/services/api/app/models/group.rb
@@ -231,7 +231,7 @@ insert into frozen_groups (uuid) select uuid from temptable where is_frozen on c
 
   def before_ownership_change
     if owner_uuid_changed? and !self.owner_uuid_was.nil?
-      MaterializedPermission.where(user_uuid: owner_uuid_was, target_uuid: uuid).delete_all
+      ComputedPermission.where(user_uuid: owner_uuid_was, target_uuid: uuid).delete_all
       update_permissions self.owner_uuid_was, self.uuid, REVOKE_PERM
     end
   end
@@ -243,7 +243,7 @@ insert into frozen_groups (uuid) select uuid from temptable where is_frozen on c
   end
 
   def clear_permissions_trash_frozen
-    MaterializedPermission.where(target_uuid: uuid).delete_all
+    ComputedPermission.where(target_uuid: uuid).delete_all
     ActiveRecord::Base.connection.exec_delete(
       "delete from trashed_groups where group_uuid=$1",
       "Group.clear_permissions_trash_frozen",
diff --git a/services/api/app/models/materialized_permission.rb b/services/api/app/models/materialized_permission.rb
deleted file mode 100644
index 24ba6737ae..0000000000
--- a/services/api/app/models/materialized_permission.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: AGPL-3.0
-
-class MaterializedPermission < ApplicationRecord
-end
diff --git a/services/api/app/models/user.rb b/services/api/app/models/user.rb
index c104ac6fda..824610b234 100644
--- a/services/api/app/models/user.rb
+++ b/services/api/app/models/user.rb
@@ -171,7 +171,7 @@ SELECT 1 FROM #{PERMISSION_VIEW}
 
   def before_ownership_change
     if owner_uuid_changed? and !self.owner_uuid_was.nil?
-      MaterializedPermission.where(user_uuid: owner_uuid_was, target_uuid: uuid).delete_all
+      ComputedPermission.where(user_uuid: owner_uuid_was, target_uuid: uuid).delete_all
       update_permissions self.owner_uuid_was, self.uuid, REVOKE_PERM
     end
   end
@@ -183,7 +183,7 @@ SELECT 1 FROM #{PERMISSION_VIEW}
   end
 
   def clear_permissions
-    MaterializedPermission.where("user_uuid = ? and target_uuid != ?", uuid, uuid).delete_all
+    ComputedPermission.where("user_uuid = ? and target_uuid != ?", uuid, uuid).delete_all
   end
 
   def forget_cached_group_perms
@@ -191,7 +191,7 @@ SELECT 1 FROM #{PERMISSION_VIEW}
   end
 
   def remove_self_from_permissions
-    MaterializedPermission.where("target_uuid = ?", uuid).delete_all
+    ComputedPermission.where("target_uuid = ?", uuid).delete_all
     check_permissions_against_full_refresh
   end
 
diff --git a/services/api/config/routes.rb b/services/api/config/routes.rb
index df3c057b57..910e6a3f29 100644
--- a/services/api/config/routes.rb
+++ b/services/api/config/routes.rb
@@ -50,7 +50,6 @@ Rails.application.routes.draw do
       end
       resources :links
       resources :logs
-      resources :workflows
       resources :user_agreements do
         get 'signatures', on: :collection
         post 'sign', on: :collection
@@ -68,6 +67,8 @@ Rails.application.routes.draw do
         get 'logins', on: :member
         get 'get_all_logins', on: :collection
       end
+      resources :workflows
+      get '/computed_permissions', to: 'computed_permissions#index'
       get '/permissions/:uuid', to: 'links#get_permissions'
     end
   end
diff --git a/services/api/lib/can_be_an_owner.rb b/services/api/lib/can_be_an_owner.rb
index 995f6f334c..f2d4d7c051 100644
--- a/services/api/lib/can_be_an_owner.rb
+++ b/services/api/lib/can_be_an_owner.rb
@@ -24,6 +24,7 @@ module CanBeAnOwner
                       'jobs',
                       'job_tasks',
                       'keep_disks',
+                      'materialized_permissions',
                       'nodes',
                       'pipeline_instances',
                       'pipeline_templates',
diff --git a/services/api/lib/record_filters.rb b/services/api/lib/record_filters.rb
index e51223254f..41a9201677 100644
--- a/services/api/lib/record_filters.rb
+++ b/services/api/lib/record_filters.rb
@@ -293,4 +293,19 @@ module RecordFilters
     {:cond_out => conds_out, :param_out => param_out, :joins => joins}
   end
 
+  def apply_filters query, filters
+    ft = record_filters filters, self
+    if not ft[:cond_out].any?
+      return query
+    end
+    ft[:joins].each do |t|
+      query = query.joins(t)
+    end
+    query.where('(' + ft[:cond_out].join(') AND (') + ')',
+                          *ft[:param_out])
+  end
+
+  def attribute_column attr
+    self.columns.select { |col| col.name == attr.to_s }.first
+  end
 end
diff --git a/services/api/test/functional/arvados/v1/computed_permissions_controller_test.rb b/services/api/test/functional/arvados/v1/computed_permissions_controller_test.rb
new file mode 100644
index 0000000000..6c89e90b63
--- /dev/null
+++ b/services/api/test/functional/arvados/v1/computed_permissions_controller_test.rb
@@ -0,0 +1,90 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
+require 'test_helper'
+
+class Arvados::V1::ComputedPermissionsControllerTest < ActionController::TestCase
+  test "require auth" do
+    get :index, params: {}
+    assert_response 401
+  end
+
+  test "require admin" do
+    authorize_with :active
+    get :index, params: {}
+    assert_response 403
+  end
+
+  test "index with no options" do
+    authorize_with :admin
+    get :index, params: {}
+    assert_response :success
+    assert_operator 0, :<, json_response['items'].length
+
+    last_user = ''
+    last_target = ''
+    json_response['items'].each do |item|
+      assert_not_empty item['user_uuid']
+      assert_not_empty item['target_uuid']
+      assert_not_empty item['perm_level']
+      # check default ordering
+      assert_operator last_user, :<=, item['user_uuid']
+      if last_user == item['user_uuid']
+        assert_operator last_target, :<=, item['target_uuid']
+      end
+      last_user = item['user_uuid']
+      last_target = item['target_uuid']
+    end
+  end
+
+  test "index with limit" do
+    authorize_with :admin
+    get :index, params: {limit: 10}
+    assert_response :success
+    assert_equal 10, json_response['items'].length
+  end
+
+  test "index with filter on user_uuid" do
+    user_uuid = users(:active).uuid
+    authorize_with :admin
+    get :index, params: {filters: [['user_uuid', '=', user_uuid]]}
+    assert_response :success
+    assert_not_equal 0, json_response['items'].length
+    json_response['items'].each do |item|
+      assert_equal user_uuid, item['user_uuid']
+    end
+  end
+
+  test "index with filter on user_uuid and target_uuid" do
+    user_uuid = users(:active).uuid
+    target_uuid = groups(:aproject).uuid
+    authorize_with :admin
+    get :index, params: {filters: [
+                           ['user_uuid', '=', user_uuid],
+                           ['target_uuid', '=', target_uuid],
+                         ]}
+    assert_response :success
+    assert_equal([{"user_uuid" => user_uuid,
+                   "target_uuid" => target_uuid,
+                   "perm_level" => "can_manage",
+                  }],
+                 json_response['items'])
+  end
+
+  test "index with disallowed filters" do
+    authorize_with :admin
+    get :index, params: {filters: [['perm_level', '=', 'can_manage']]}
+    assert_response 422
+  end
+
+  %w(user_uuid target_uuid perm_level).each do |attr|
+    test "select only #{attr}" do
+      authorize_with :admin
+      get :index, params: {select: [attr], limit: 1}
+      assert_response :success
+      assert_operator 0, :<, json_response['items'][0][attr].length
+      assert_equal([{attr => json_response['items'][0][attr]}], json_response['items'])
+    end
+  end
+end
diff --git a/services/api/test/integration/computed_permissions_test.rb b/services/api/test/integration/computed_permissions_test.rb
new file mode 100644
index 0000000000..803c7fef68
--- /dev/null
+++ b/services/api/test/integration/computed_permissions_test.rb
@@ -0,0 +1,28 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
+require 'test_helper'
+
+class ComputedPermissionsTest < ActionDispatch::IntegrationTest
+  include DbCurrentTime
+  fixtures :users, :groups, :api_client_authorizations, :collections
+
+  test "non-admin forbidden" do
+    get "/arvados/v1/computed_permissions",
+      params: {:format => :json},
+      headers: auth(:active)
+    assert_response 403
+  end
+
+  test "admin get permission for specified user" do
+    get "/arvados/v1/computed_permissions",
+      params: {
+        :format => :json,
+        :filters => [['user_uuid', '=', users(:active).uuid]].to_json,
+      },
+      headers: auth(:admin)
+    assert_response :success
+    assert_equal users(:active).uuid, json_response['items'][0]['user_uuid']
+  end
+end
diff --git a/services/api/test/integration/discovery_document_test.rb b/services/api/test/integration/discovery_document_test.rb
index 37e7750297..e29c4416b3 100644
--- a/services/api/test/integration/discovery_document_test.rb
+++ b/services/api/test/integration/discovery_document_test.rb
@@ -49,10 +49,9 @@ class DiscoveryDocumentTest < ActionDispatch::IntegrationTest
     if expected_json != actual_json
       File.open(out_path, "w") { |f| f.write(actual_json) }
     end
-    assert_equal(expected_json, actual_json, [
-                   "#{src_path} did not match the live discovery document",
-                   "Current live version saved to #{out_path}",
-                   "Commit that to #{src_path} to regenerate documentation",
-                 ].join(". "))
+    assert_equal(expected_json, actual_json,
+                 "Live discovery document did not match the expected version (#{src_path}). " +
+                 "If the live version is correct, copy it to the git working directory by running:\n" +
+                 "cp #{out_path} #{src_path}\n")
   end
 end

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list