Add a policy to control the right to publish resources
This change intends to add the following policies: - actions:publicize - workflows:publicize A refactor of the policy tests is included to increase the coverage. Change-Id: I8bd637f7de63f02c63f3c304cb6f5198fc0c5f42 Closes-Bug: 1779293
This commit is contained in:
parent
2bfc9d1ad8
commit
522f388709
@ -83,6 +83,8 @@ class ActionsController(rest.RestController, hooks.HookController):
|
|||||||
|
|
||||||
scope = pecan.request.GET.get('scope', 'private')
|
scope = pecan.request.GET.get('scope', 'private')
|
||||||
resources.Action.validate_scope(scope)
|
resources.Action.validate_scope(scope)
|
||||||
|
if scope == 'public':
|
||||||
|
acl.enforce('actions:publicize', context.ctx())
|
||||||
|
|
||||||
@rest_utils.rest_retry_on_db_error
|
@rest_utils.rest_retry_on_db_error
|
||||||
def _update_actions():
|
def _update_actions():
|
||||||
@ -116,6 +118,8 @@ class ActionsController(rest.RestController, hooks.HookController):
|
|||||||
pecan.response.status = 201
|
pecan.response.status = 201
|
||||||
|
|
||||||
resources.Action.validate_scope(scope)
|
resources.Action.validate_scope(scope)
|
||||||
|
if scope == 'public':
|
||||||
|
acl.enforce('actions:publicize', context.ctx())
|
||||||
|
|
||||||
LOG.debug("Create action(s) [definition=%s]", definition)
|
LOG.debug("Create action(s) [definition=%s]", definition)
|
||||||
|
|
||||||
|
@ -117,6 +117,8 @@ class WorkflowsController(rest.RestController, hooks.HookController):
|
|||||||
scope = pecan.request.GET.get('scope', 'private')
|
scope = pecan.request.GET.get('scope', 'private')
|
||||||
|
|
||||||
resources.Workflow.validate_scope(scope)
|
resources.Workflow.validate_scope(scope)
|
||||||
|
if scope == 'public':
|
||||||
|
acl.enforce('workflows:publicize', context.ctx())
|
||||||
|
|
||||||
LOG.debug("Update workflow(s) [definition=%s]", definition)
|
LOG.debug("Update workflow(s) [definition=%s]", definition)
|
||||||
|
|
||||||
@ -153,6 +155,8 @@ class WorkflowsController(rest.RestController, hooks.HookController):
|
|||||||
pecan.response.status = 201
|
pecan.response.status = 201
|
||||||
|
|
||||||
resources.Workflow.validate_scope(scope)
|
resources.Workflow.validate_scope(scope)
|
||||||
|
if scope == 'public':
|
||||||
|
acl.enforce('workflows:publicize', context.ctx())
|
||||||
|
|
||||||
LOG.debug("Create workflow(s) [definition=%s]", definition)
|
LOG.debug("Create workflow(s) [definition=%s]", definition)
|
||||||
|
|
||||||
|
@ -62,6 +62,21 @@ rules = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
policy.DocumentedRuleDefault(
|
||||||
|
name=ACTIONS % 'publicize',
|
||||||
|
check_str=base.RULE_ADMIN_OR_OWNER,
|
||||||
|
description='Make an action publicly available',
|
||||||
|
operations=[
|
||||||
|
{
|
||||||
|
'path': '/v2/actions',
|
||||||
|
'method': 'POST'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/v2/actions',
|
||||||
|
'method': 'PUT'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
),
|
||||||
policy.DocumentedRuleDefault(
|
policy.DocumentedRuleDefault(
|
||||||
name=ACTIONS % 'update',
|
name=ACTIONS % 'update',
|
||||||
check_str=base.RULE_ADMIN_OR_OWNER,
|
check_str=base.RULE_ADMIN_OR_OWNER,
|
||||||
|
@ -73,6 +73,21 @@ rules = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
policy.DocumentedRuleDefault(
|
||||||
|
name=WORKFLOWS % 'publicize',
|
||||||
|
check_str=base.RULE_ADMIN_OR_OWNER,
|
||||||
|
description='Make a workflow publicly available',
|
||||||
|
operations=[
|
||||||
|
{
|
||||||
|
'path': '/v2/workflows',
|
||||||
|
'method': 'POST'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/v2/workflows',
|
||||||
|
'method': 'PUT'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
),
|
||||||
policy.DocumentedRuleDefault(
|
policy.DocumentedRuleDefault(
|
||||||
name=WORKFLOWS % 'update',
|
name=WORKFLOWS % 'update',
|
||||||
check_str=base.RULE_ADMIN_OR_OWNER,
|
check_str=base.RULE_ADMIN_OR_OWNER,
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
# Copyright 2016 NEC Corporation. All rights reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
import mock
|
|
||||||
|
|
||||||
from mistral.db.v2 import api as db_api
|
|
||||||
from mistral.db.v2.sqlalchemy import models
|
|
||||||
from mistral.tests.unit.api import base
|
|
||||||
from mistral.tests.unit.mstrlfixtures import policy_fixtures
|
|
||||||
|
|
||||||
WF_DEFINITION = """
|
|
||||||
---
|
|
||||||
version: '2.0'
|
|
||||||
|
|
||||||
flow:
|
|
||||||
type: direct
|
|
||||||
input:
|
|
||||||
- param1
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
task1:
|
|
||||||
action: std.echo output="Hi"
|
|
||||||
"""
|
|
||||||
|
|
||||||
WF_DB = models.WorkflowDefinition(
|
|
||||||
id='123e4567-e89b-12d3-a456-426655440000',
|
|
||||||
name='flow',
|
|
||||||
definition=WF_DEFINITION,
|
|
||||||
created_at=datetime.datetime(1970, 1, 1),
|
|
||||||
updated_at=datetime.datetime(1970, 1, 1),
|
|
||||||
spec={'input': ['param1']}
|
|
||||||
)
|
|
||||||
|
|
||||||
WF = {
|
|
||||||
'id': '123e4567-e89b-12d3-a456-426655440000',
|
|
||||||
'name': 'flow',
|
|
||||||
'definition': WF_DEFINITION,
|
|
||||||
'created_at': '1970-01-01 00:00:00',
|
|
||||||
'updated_at': '1970-01-01 00:00:00',
|
|
||||||
'input': 'param1'
|
|
||||||
}
|
|
||||||
|
|
||||||
MOCK_WF = mock.MagicMock(return_value=WF_DB)
|
|
||||||
|
|
||||||
|
|
||||||
class TestPolicies(base.APITest):
|
|
||||||
@mock.patch.object(db_api, "get_workflow_definition", MOCK_WF)
|
|
||||||
def get(self):
|
|
||||||
resp = self.app.get('/v2/workflows/123', expect_errors=True)
|
|
||||||
return resp.status_int
|
|
||||||
|
|
||||||
def test_disable_workflow_api(self):
|
|
||||||
self.policy = self.useFixture(policy_fixtures.PolicyFixture())
|
|
||||||
rules = {"workflows:get": "role:FAKE"}
|
|
||||||
self.policy.change_policy_definition(rules)
|
|
||||||
response_value = self.get()
|
|
||||||
self.assertEqual(403, response_value)
|
|
||||||
|
|
||||||
def test_enable_workflow_api(self):
|
|
||||||
self.policy = self.useFixture(policy_fixtures.PolicyFixture())
|
|
||||||
rules = {"workflows:get": "role:FAKE or rule:admin_or_owner"}
|
|
||||||
self.policy.change_policy_definition(rules)
|
|
||||||
response_value = self.get()
|
|
||||||
self.assertEqual(200, response_value)
|
|
0
mistral/tests/unit/policies/__init__.py
Normal file
0
mistral/tests/unit/policies/__init__.py
Normal file
249
mistral/tests/unit/policies/test_actions.py
Normal file
249
mistral/tests/unit/policies/test_actions.py
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
# Copyright 2018 OVH SAS. All rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from mistral.db.v2 import api as db_api
|
||||||
|
from mistral.db.v2.sqlalchemy import models
|
||||||
|
from mistral.tests.unit.api import base
|
||||||
|
from mistral.tests.unit.mstrlfixtures import policy_fixtures
|
||||||
|
|
||||||
|
MOCK_DELETE = mock.MagicMock(return_value=None)
|
||||||
|
|
||||||
|
ACTION_DEFINITION = """
|
||||||
|
---
|
||||||
|
version: '2.0'
|
||||||
|
|
||||||
|
my_action:
|
||||||
|
description: My super cool action.
|
||||||
|
tags: ['test', 'v2']
|
||||||
|
base: std.echo
|
||||||
|
base-input:
|
||||||
|
output: "{$.str1}{$.str2}"
|
||||||
|
"""
|
||||||
|
ACTION_DB = models.ActionDefinition(
|
||||||
|
id='123e4567-e89b-12d3-a456-426655440000',
|
||||||
|
name='my_action',
|
||||||
|
is_system=False,
|
||||||
|
description='My super cool action.',
|
||||||
|
tags=['test', 'v2'],
|
||||||
|
definition=ACTION_DEFINITION
|
||||||
|
)
|
||||||
|
MOCK_ACTION = mock.MagicMock(return_value=ACTION_DB)
|
||||||
|
|
||||||
|
|
||||||
|
class TestActionPolicy(base.APITest):
|
||||||
|
"""Test action related policies
|
||||||
|
|
||||||
|
Policies to test:
|
||||||
|
- actions:create
|
||||||
|
- actions:delete
|
||||||
|
- actions:get
|
||||||
|
- actions:list
|
||||||
|
- actions:publicize (on POST & PUT)
|
||||||
|
- actions:update
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.policy = self.useFixture(policy_fixtures.PolicyFixture())
|
||||||
|
super(TestActionPolicy, self).setUp()
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "create_action_definition")
|
||||||
|
def test_action_create_not_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"actions:create": "role:FAKE"}
|
||||||
|
)
|
||||||
|
resp = self.app.post(
|
||||||
|
'/v2/actions',
|
||||||
|
ACTION_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(403, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "create_action_definition")
|
||||||
|
def test_action_create_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"actions:create": "role:FAKE or rule:admin_or_owner"}
|
||||||
|
)
|
||||||
|
resp = self.app.post(
|
||||||
|
'/v2/actions',
|
||||||
|
ACTION_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(201, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "create_action_definition")
|
||||||
|
def test_action_create_public_not_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition({
|
||||||
|
"actions:create": "role:FAKE or rule:admin_or_owner",
|
||||||
|
"actions:publicize": "role:FAKE"
|
||||||
|
})
|
||||||
|
resp = self.app.post(
|
||||||
|
'/v2/actions?scope=public',
|
||||||
|
ACTION_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(403, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "create_action_definition")
|
||||||
|
def test_action_create_public_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition({
|
||||||
|
"actions:create": "role:FAKE or rule:admin_or_owner",
|
||||||
|
"actions:publicize": "role:FAKE or rule:admin_or_owner"
|
||||||
|
})
|
||||||
|
resp = self.app.post(
|
||||||
|
'/v2/actions?scope=public',
|
||||||
|
ACTION_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(201, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "delete_action_definition", MOCK_DELETE)
|
||||||
|
@mock.patch.object(db_api, "get_action_definition", MOCK_ACTION)
|
||||||
|
def test_action_delete_not_allowed(self):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"actions:delete": "role:FAKE"}
|
||||||
|
)
|
||||||
|
resp = self.app.delete(
|
||||||
|
'/v2/actions/123',
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(403, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "delete_action_definition", MOCK_DELETE)
|
||||||
|
@mock.patch.object(db_api, "get_action_definition", MOCK_ACTION)
|
||||||
|
def test_action_delete_allowed(self):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"actions:delete": "role:FAKE or rule:admin_or_owner"}
|
||||||
|
)
|
||||||
|
resp = self.app.delete(
|
||||||
|
'/v2/actions/123',
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(204, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "get_action_definition", MOCK_ACTION)
|
||||||
|
def test_action_get_not_allowed(self):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"actions:get": "role:FAKE"}
|
||||||
|
)
|
||||||
|
resp = self.app.get(
|
||||||
|
'/v2/actions/123',
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(403, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "get_action_definition", MOCK_ACTION)
|
||||||
|
def test_action_get_allowed(self):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"actions:get": "role:FAKE or rule:admin_or_owner"}
|
||||||
|
)
|
||||||
|
resp = self.app.get(
|
||||||
|
'/v2/actions/123',
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, resp.status_int)
|
||||||
|
|
||||||
|
def test_action_list_not_allowed(self):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"actions:list": "role:FAKE"}
|
||||||
|
)
|
||||||
|
resp = self.app.get(
|
||||||
|
'/v2/actions',
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(403, resp.status_int)
|
||||||
|
|
||||||
|
def test_action_list_allowed(self):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"actions:list": "role:FAKE or rule:admin_or_owner"}
|
||||||
|
)
|
||||||
|
resp = self.app.get(
|
||||||
|
'/v2/actions',
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "update_action_definition")
|
||||||
|
def test_action_update_not_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"actions:update": "role:FAKE"}
|
||||||
|
)
|
||||||
|
resp = self.app.put(
|
||||||
|
'/v2/actions',
|
||||||
|
ACTION_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(403, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "update_action_definition")
|
||||||
|
def test_action_update_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"actions:update": "role:FAKE or rule:admin_or_owner"}
|
||||||
|
)
|
||||||
|
resp = self.app.put(
|
||||||
|
'/v2/actions',
|
||||||
|
ACTION_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "update_action_definition")
|
||||||
|
def test_action_update_public_not_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition({
|
||||||
|
"actions:update": "role:FAKE or rule:admin_or_owner",
|
||||||
|
"actions:publicize": "role:FAKE"
|
||||||
|
})
|
||||||
|
resp = self.app.put(
|
||||||
|
'/v2/actions?scope=public',
|
||||||
|
ACTION_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(403, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "update_action_definition")
|
||||||
|
def test_action_update_public_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition({
|
||||||
|
"actions:update": "role:FAKE or rule:admin_or_owner",
|
||||||
|
"actions:publicize": "role:FAKE or rule:admin_or_owner"
|
||||||
|
})
|
||||||
|
resp = self.app.put(
|
||||||
|
'/v2/actions?scope=public',
|
||||||
|
ACTION_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, resp.status_int)
|
279
mistral/tests/unit/policies/test_workflows.py
Normal file
279
mistral/tests/unit/policies/test_workflows.py
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
# Copyright 2016 NEC Corporation. All rights reserved.
|
||||||
|
# Copyright 2018 OVH SAS. All rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from mistral.db.v2 import api as db_api
|
||||||
|
from mistral.db.v2.sqlalchemy import models
|
||||||
|
from mistral.tests.unit.api import base
|
||||||
|
from mistral.tests.unit.mstrlfixtures import policy_fixtures
|
||||||
|
|
||||||
|
MOCK_DELETE = mock.MagicMock(return_value=None)
|
||||||
|
|
||||||
|
WF_DEFINITION = """
|
||||||
|
---
|
||||||
|
version: '2.0'
|
||||||
|
|
||||||
|
flow:
|
||||||
|
type: direct
|
||||||
|
input:
|
||||||
|
- param1
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
task1:
|
||||||
|
action: std.echo output="Hi"
|
||||||
|
"""
|
||||||
|
WF_DB = models.WorkflowDefinition(
|
||||||
|
id='123e4567-e89b-12d3-a456-426655440000',
|
||||||
|
name='flow',
|
||||||
|
definition=WF_DEFINITION,
|
||||||
|
created_at=datetime.datetime(1970, 1, 1),
|
||||||
|
updated_at=datetime.datetime(1970, 1, 1),
|
||||||
|
spec={'input': ['param1']}
|
||||||
|
)
|
||||||
|
MOCK_WF = mock.MagicMock(return_value=WF_DB)
|
||||||
|
|
||||||
|
|
||||||
|
class TestWorkflowPolicy(base.APITest):
|
||||||
|
"""Test workflow related policies
|
||||||
|
|
||||||
|
Policies to test:
|
||||||
|
- workflows:create
|
||||||
|
- workflows:delete
|
||||||
|
- workflows:get
|
||||||
|
- workflows:list
|
||||||
|
- workflows:list:all_projects
|
||||||
|
- workflows:publicize (on POST & PUT)
|
||||||
|
- workflows:update
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.policy = self.useFixture(policy_fixtures.PolicyFixture())
|
||||||
|
super(TestWorkflowPolicy, self).setUp()
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "create_workflow_definition")
|
||||||
|
def test_workflow_create_not_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"workflows:create": "role:FAKE"}
|
||||||
|
)
|
||||||
|
resp = self.app.post(
|
||||||
|
'/v2/workflows',
|
||||||
|
WF_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(403, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "create_workflow_definition")
|
||||||
|
def test_workflow_create_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"workflows:create": "role:FAKE or rule:admin_or_owner"}
|
||||||
|
)
|
||||||
|
resp = self.app.post(
|
||||||
|
'/v2/workflows',
|
||||||
|
WF_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(201, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "create_workflow_definition")
|
||||||
|
def test_workflow_create_public_not_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition({
|
||||||
|
"workflows:create": "role:FAKE or rule:admin_or_owner",
|
||||||
|
"workflows:publicize": "role:FAKE"
|
||||||
|
})
|
||||||
|
resp = self.app.post(
|
||||||
|
'/v2/workflows?scope=public',
|
||||||
|
WF_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(403, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "create_workflow_definition")
|
||||||
|
def test_workflow_create_public_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition({
|
||||||
|
"workflows:create": "role:FAKE or rule:admin_or_owner",
|
||||||
|
"workflows:publicize": "role:FAKE or rule:admin_or_owner"
|
||||||
|
})
|
||||||
|
resp = self.app.post(
|
||||||
|
'/v2/workflows?scope=public',
|
||||||
|
WF_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(201, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "delete_workflow_definition", MOCK_DELETE)
|
||||||
|
@mock.patch.object(db_api, "get_workflow_definition", MOCK_WF)
|
||||||
|
def test_workflow_delete_not_allowed(self):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"workflows:delete": "role:FAKE"}
|
||||||
|
)
|
||||||
|
resp = self.app.delete(
|
||||||
|
'/v2/workflows/123',
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(403, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "delete_workflow_definition", MOCK_DELETE)
|
||||||
|
@mock.patch.object(db_api, "get_workflow_definition", MOCK_WF)
|
||||||
|
def test_workflow_delete_allowed(self):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"workflows:delete": "role:FAKE or rule:admin_or_owner"}
|
||||||
|
)
|
||||||
|
resp = self.app.delete(
|
||||||
|
'/v2/workflows/123',
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(204, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "get_workflow_definition", MOCK_WF)
|
||||||
|
def test_workflow_get_not_allowed(self):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"workflows:get": "role:FAKE"}
|
||||||
|
)
|
||||||
|
resp = self.app.get(
|
||||||
|
'/v2/workflows/123',
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(403, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "get_workflow_definition", MOCK_WF)
|
||||||
|
def test_workflow_get_allowed(self):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"workflows:get": "role:FAKE or rule:admin_or_owner"}
|
||||||
|
)
|
||||||
|
resp = self.app.get(
|
||||||
|
'/v2/workflows/123',
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, resp.status_int)
|
||||||
|
|
||||||
|
def test_workflow_list_not_allowed(self):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"workflows:list": "role:FAKE"}
|
||||||
|
)
|
||||||
|
resp = self.app.get(
|
||||||
|
'/v2/workflows',
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(403, resp.status_int)
|
||||||
|
|
||||||
|
def test_workflow_list_allowed(self):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"workflows:list": "role:FAKE or rule:admin_or_owner"}
|
||||||
|
)
|
||||||
|
resp = self.app.get(
|
||||||
|
'/v2/workflows',
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, resp.status_int)
|
||||||
|
|
||||||
|
def test_workflow_list_all_not_allowed(self):
|
||||||
|
self.policy.change_policy_definition({
|
||||||
|
"workflows:list": "role:FAKE or rule:admin_or_owner",
|
||||||
|
"workflows:list:all_projects": "role:FAKE"
|
||||||
|
})
|
||||||
|
resp = self.app.get(
|
||||||
|
'/v2/workflows?all_projects=1',
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(403, resp.status_int)
|
||||||
|
|
||||||
|
def test_workflow_list_all_allowed(self):
|
||||||
|
self.policy.change_policy_definition({
|
||||||
|
"workflows:list": "role:FAKE or rule:admin_or_owner",
|
||||||
|
"workflows:list:all_projects": "role:FAKE or rule:admin_or_owner"
|
||||||
|
})
|
||||||
|
resp = self.app.get(
|
||||||
|
'/v2/workflows?all_projects=1',
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "update_workflow_definition")
|
||||||
|
def test_workflow_update_not_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"workflows:update": "role:FAKE"}
|
||||||
|
)
|
||||||
|
resp = self.app.put(
|
||||||
|
'/v2/workflows',
|
||||||
|
WF_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(403, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "update_workflow_definition")
|
||||||
|
def test_workflow_update_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition(
|
||||||
|
{"workflows:update": "role:FAKE or rule:admin_or_owner"}
|
||||||
|
)
|
||||||
|
resp = self.app.put(
|
||||||
|
'/v2/workflows',
|
||||||
|
WF_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "update_workflow_definition")
|
||||||
|
def test_workflow_update_public_not_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition({
|
||||||
|
"workflows:update": "role:FAKE or rule:admin_or_owner",
|
||||||
|
"workflows:publicize": "role:FAKE"
|
||||||
|
})
|
||||||
|
resp = self.app.put(
|
||||||
|
'/v2/workflows?scope=public',
|
||||||
|
WF_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(403, resp.status_int)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, "update_workflow_definition")
|
||||||
|
def test_workflow_update_public_allowed(self, mock_obj):
|
||||||
|
self.policy.change_policy_definition({
|
||||||
|
"workflows:update": "role:FAKE or rule:admin_or_owner",
|
||||||
|
"workflows:publicize": "role:FAKE or rule:admin_or_owner"
|
||||||
|
})
|
||||||
|
resp = self.app.put(
|
||||||
|
'/v2/workflows?scope=public',
|
||||||
|
WF_DEFINITION,
|
||||||
|
headers={'Content-Type': 'text/plain'},
|
||||||
|
expect_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, resp.status_int)
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Mistral now supports a `publicize` policy on actions and workflows which
|
||||||
|
controls whether the users are allowed to create or update them. The
|
||||||
|
default policy does not change which means that everyone can publish
|
||||||
|
action or workflow unless specified differently in the policy.
|
Loading…
x
Reference in New Issue
Block a user