Revision d9e7b2c35422382ed411623e741b1462d671f456 authored by Kirill Lakhov on 19 December 2023, 14:25:41 UTC, committed by GitHub on 19 December 2023, 14:25:41 UTC
1 parent 48ab12b
test_webhooks.py
# Copyright (C) 2022-2023 CVAT.ai Corporation
#
# SPDX-License-Identifier: MIT
from copy import deepcopy
from http import HTTPStatus
from itertools import product
import pytest
from cvat_sdk.api_client.api_client import ApiClient, Endpoint
from deepdiff import DeepDiff
from shared.utils.config import delete_method, get_method, patch_method, post_method
from .utils import CollectionSimpleFilterTestBase
@pytest.mark.usefixtures("restore_db_per_function")
class TestPostWebhooks:
proj_webhook = {
"description": "webhook description",
"content_type": "application/json",
"enable_ssl": False,
"events": ["create:task", "delete:task"],
"is_active": True,
"project_id": 1,
"secret": "secret",
"target_url": "http://example.com",
"type": "project",
}
org_webhook = {
"description": "webhook description",
"content_type": "application/json",
"enable_ssl": False,
"events": ["create:task", "delete:task"],
"is_active": True,
"secret": "secret",
"target_url": "http://example.com",
"type": "organization",
}
def test_sandbox_admin_can_create_webhook_for_project(self, projects, users):
admin = next((u for u in users if "admin" in u["groups"]))
project = [
p for p in projects if p["owner"]["id"] != admin["id"] and p["organization"] is None
][0]
webhook = deepcopy(self.proj_webhook)
webhook["project_id"] = project["id"]
response = post_method(admin["username"], "webhooks", webhook)
assert response.status_code == HTTPStatus.CREATED
assert "secret" not in response.json()
def test_admin_can_create_webhook_for_org(self, users, organizations, is_org_member):
admins = [u for u in users if "admin" in u["groups"]]
username, org_id = next(
(
(user["username"], org["id"])
for user in admins
for org in organizations
if not is_org_member(user["id"], org["id"])
)
)
webhook = deepcopy(self.org_webhook)
response = post_method(username, "webhooks", webhook, org_id=org_id)
assert response.status_code == HTTPStatus.CREATED
assert "secret" not in response.json()
def test_admin_can_create_webhook_for_project_in_org(
self, users, projects_by_org, organizations, is_org_member
):
admins = [u for u in users if "admin" in u["groups"]]
not_org_members = [
(u, o) for u, o in product(admins, organizations) if not is_org_member(u["id"], o["id"])
]
username, org_id = next(
(
(u["username"], o["id"])
for u, o in not_org_members
for p in projects_by_org.get(o["id"], [])
if p["owner"]["id"] != u["id"]
)
)
webhook = deepcopy(self.org_webhook)
response = post_method(username, "webhooks", webhook, org_id=org_id)
assert response.status_code == HTTPStatus.CREATED
assert "secret" not in response.json()
@pytest.mark.parametrize("privilege", ["user", "business"])
def test_sandbox_project_owner_can_create_webhook_for_project(self, privilege, projects, users):
users = [user for user in users if privilege in user["groups"]]
username, project_id = next(
(
(user["username"], project["id"])
for user in users
for project in projects
if project["owner"]["id"] == user["id"] and project["organization"] is None
)
)
webhook = deepcopy(self.proj_webhook)
webhook["project_id"] = project_id
response = post_method(username, "webhooks", webhook)
assert response.status_code == HTTPStatus.CREATED
assert "secret" not in response.json()
@pytest.mark.parametrize("privilege", ["worker", "user", "business"])
def test_sandbox_project_assignee_cannot_create_webhook_for_project(
self, privilege, projects, users
):
users = [u for u in users if privilege in u["groups"]]
projects = [p for p in projects if p["assignee"] is not None]
username, project_id = next(
(
(user["username"], project["id"])
for user in users
for project in projects
if project["assignee"]["id"] == user["id"] and project["organization"] is None
)
)
webhook = deepcopy(self.proj_webhook)
webhook["project_id"] = project_id
response = post_method(username, "webhooks", webhook)
assert response.status_code == HTTPStatus.FORBIDDEN
@pytest.mark.parametrize("role", ["maintainer", "owner"])
def test_member_can_create_webhook_for_org(self, role, find_users, organizations):
username, org_id = next(
(
(u["username"], o["id"])
for o in organizations
for u in find_users(org=o["id"], role=role, exclude_privilege="admin")
)
)
webhook = deepcopy(self.org_webhook)
response = post_method(username, "webhooks", webhook, org_id=org_id)
assert response.status_code == HTTPStatus.CREATED
assert "secret" not in response.json()
@pytest.mark.parametrize("role", ["maintainer", "owner"])
def test_member_can_create_webhook_for_project(
self, role, find_users, organizations, projects_by_org, is_project_staff
):
username, oid, pid = next(
(
(u["username"], o["id"], p["id"])
for o in organizations
for u in find_users(org=o["id"], role=role, exclude_privilege="admin")
for p in projects_by_org.get(o["id"], [])
if not is_project_staff(u["id"], p["id"])
)
)
webhook = deepcopy(self.proj_webhook)
webhook["project_id"] = pid
response = post_method(username, "webhooks", webhook, org_id=oid)
assert response.status_code == HTTPStatus.CREATED
assert "secret" not in response.json()
@pytest.mark.parametrize("role", ["supervisor", "worker"])
def test_member_cannot_create_webhook_for_org(self, role, find_users, organizations):
username, org_id = next(
(
(u["username"], o["id"])
for o in organizations
for u in find_users(org=o["id"], role=role, exclude_privilege="admin")
)
)
webhook = deepcopy(self.org_webhook)
response = post_method(username, "webhooks", webhook, org_id=org_id)
assert response.status_code == HTTPStatus.FORBIDDEN
@pytest.mark.parametrize("role", ["supervisor", "worker"])
def test_member_cannot_create_webhook_for_project(
self, role, find_users, organizations, projects_by_org, is_project_staff
):
username, oid, pid = next(
(
(u["username"], o["id"], p["id"])
for o in organizations
for u in find_users(org=o["id"], role=role, exclude_privilege="admin")
for p in projects_by_org.get(o["id"], [])
if not is_project_staff(u["id"], p["id"])
)
)
webhook = deepcopy(self.proj_webhook)
webhook["project_id"] = pid
response = post_method(username, "webhooks", webhook, org_id=oid)
assert response.status_code == HTTPStatus.FORBIDDEN
@pytest.mark.parametrize("role", ["supervisor"])
def test_member_project_owner_can_create_webhook_for_project(
self, role, find_users, organizations, projects_by_org, is_project_staff
):
username, oid, pid = next(
(
(u["username"], o["id"], p["id"])
for o in organizations
for u in find_users(org=o["id"], role=role, exclude_privilege="admin")
for p in projects_by_org.get(o["id"], [])
if p["owner"]["id"] == u["id"]
)
)
webhook = deepcopy(self.proj_webhook)
webhook["project_id"] = pid
response = post_method(username, "webhooks", webhook, org_id=oid)
assert response.status_code == HTTPStatus.CREATED
assert "secret" not in response.json()
def test_non_member_cannot_create_webhook_for_org(
self, find_users, organizations, is_org_member
):
username, org_id = next(
(
(u["username"], o["id"])
for o in organizations
for u in find_users(exclude_privilege="admin")
if not is_org_member(u["id"], o["id"])
)
)
webhook = deepcopy(self.org_webhook)
response = post_method(username, "webhooks", webhook, org_id=org_id)
assert response.status_code == HTTPStatus.FORBIDDEN
def test_can_create_without_unnecessary_fields(self):
post_data = deepcopy(self.proj_webhook)
post_data.pop("enable_ssl")
post_data.pop("content_type")
post_data.pop("description")
post_data.pop("is_active")
post_data.pop("secret")
response = post_method("admin2", "webhooks", post_data)
assert response.status_code == HTTPStatus.CREATED
def test_can_create_with_mismatching_project_org_fields(self, projects_by_org):
# In this case we could either fail or ignore invalid query param
# Currently, the invalid org id will be ignored and the value
# will be taken from the project.
post_data = deepcopy(self.proj_webhook)
org_id = next(iter(projects_by_org))
project = projects_by_org[org_id][0]
post_data["project_id"] = project["id"]
org_id = next(k for k in projects_by_org if k != org_id)
response = post_method("admin1", "webhooks", post_data, org_id=org_id)
assert response.status_code == HTTPStatus.CREATED
assert response.json()["project_id"] == post_data["project_id"]
assert response.json()["organization"] == project["organization"]
def test_cannot_create_without_target_url(self):
post_data = deepcopy(self.proj_webhook)
post_data.pop("target_url")
response = post_method("admin2", "webhooks", post_data)
assert response.status_code == HTTPStatus.BAD_REQUEST
def test_cannot_create_without_events_list(self):
post_data = deepcopy(self.proj_webhook)
post_data.pop("events")
response = post_method("admin2", "webhooks", post_data)
assert response.status_code == HTTPStatus.BAD_REQUEST
def test_cannot_create_without_type(self):
post_data = deepcopy(self.proj_webhook)
post_data.pop("type")
response = post_method("admin2", "webhooks", post_data)
assert response.status_code == HTTPStatus.BAD_REQUEST
def test_cannot_create_without_project_id(self):
post_data = deepcopy(self.proj_webhook)
post_data.pop("project_id")
response = post_method("admin2", "webhooks", post_data)
assert response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR
def test_cannot_create_organization_webhook_when_project_id_is_not_null(self, organizations):
post_data = deepcopy(self.proj_webhook)
post_data["type"] = "organization"
org_id = organizations.raw[0]["id"]
response = post_method("admin2", "webhooks", post_data, org_id=org_id)
assert response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR
@pytest.mark.skip("Not implemented yet")
def test_cannot_create_non_unique_webhook(self):
response = post_method("admin2", "webhooks", self.proj_webhook)
response = post_method("admin2", "webhooks", self.proj_webhook)
assert response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR
def test_cannot_create_for_non_existent_organization(self, organizations):
post_data = deepcopy(self.proj_webhook)
post_data["type"] = "organization"
org_id = max(a["id"] for a in organizations.raw) + 1
response = post_method("admin2", "webhooks", post_data, org_id=org_id)
assert response.status_code == HTTPStatus.NOT_FOUND
def test_cannot_create_for_non_existent_project(self, projects):
post_data = deepcopy(self.proj_webhook)
post_data["project_id"] = max(a["id"] for a in projects.raw) + 1
response = post_method("admin2", "webhooks", post_data)
assert response.status_code == HTTPStatus.BAD_REQUEST
def test_cannot_create_with_non_supported_type(self):
post_data = deepcopy(self.proj_webhook)
post_data["type"] = "some_type"
response = post_method("admin2", "webhooks", post_data)
assert response.status_code == HTTPStatus.BAD_REQUEST
def test_cannot_create_with_non_supported_content_type(self):
post_data = deepcopy(self.proj_webhook)
post_data["content_type"] = ["application/x-www-form-urlencoded"]
response = post_method("admin2", "webhooks", post_data)
assert response.status_code == HTTPStatus.BAD_REQUEST
@pytest.mark.parametrize(
"event", ["some:event", "create:project", "update:organization", "create:invitation"]
)
def test_cannot_create_project_webhook_with_non_supported_event_type(self, event):
post_data = deepcopy(self.proj_webhook)
post_data["events"] = [event]
response = post_method("admin2", "webhooks", post_data)
assert response.status_code == HTTPStatus.BAD_REQUEST
@pytest.mark.parametrize("event", ["some:event", "create:organization"])
def test_cannot_create_organization_webhook_with_non_supported_event_type(
self, event, organizations
):
post_data = deepcopy(self.proj_webhook)
post_data["type"] = "organization"
post_data["events"] = [event]
org_id = next(iter(organizations))["id"]
response = post_method("admin2", "webhooks", post_data, org_id=org_id)
assert response.status_code == HTTPStatus.BAD_REQUEST
@pytest.mark.usefixtures("restore_db_per_class")
class TestGetWebhooks:
def test_admin_can_get_webhook(self, webhooks, users, projects):
proj_webhooks = [w for w in webhooks if w["type"] == "project"]
username, wid = next(
(
(user["username"], webhook["id"])
for user in users
for webhook in proj_webhooks
if "admin" in user["groups"]
and webhook["owner"]["id"] != user["id"]
and projects[webhook["project_id"]]["owner"]["id"] != user["id"]
)
)
response = get_method(username, f"webhooks/{wid}")
assert response.status_code == HTTPStatus.OK
assert "secret" not in response.json()
assert DeepDiff(webhooks[wid], response.json(), ignore_order=True) == {}
@pytest.mark.parametrize("privilege", ["user", "business"])
def test_project_owner_can_get_webhook(self, privilege, webhooks, projects, users):
proj_webhooks = [w for w in webhooks if w["type"] == "project"]
username, wid = next(
(
(user["username"], webhook["id"])
for user in users
for webhook in proj_webhooks
if privilege not in user["groups"]
and projects[webhook["project_id"]]["owner"]["id"] == user["id"]
)
)
response = get_method(username, f"webhooks/{wid}")
assert response.status_code == HTTPStatus.OK
assert "secret" not in response.json()
assert DeepDiff(webhooks[wid], response.json(), ignore_order=True) == {}
@pytest.mark.parametrize("privilege", ["user", "business"])
def test_webhook_owner_can_get_webhook(self, privilege, webhooks, projects, users):
proj_webhooks = [w for w in webhooks if w["type"] == "project"]
username, wid = next(
(
(user["username"], webhook["id"])
for user in users
for webhook in proj_webhooks
if privilege in user["groups"] and webhook["owner"]["id"] == user["id"]
)
)
response = get_method(username, f"webhooks/{wid}")
assert response.status_code == HTTPStatus.OK
assert "secret" not in response.json()
assert DeepDiff(webhooks[wid], response.json(), ignore_order=True) == {}
@pytest.mark.parametrize("privilege", ["user", "business"])
def test_not_project_staff_cannot_get_webhook(self, privilege, webhooks, projects, users):
proj_webhooks = [w for w in webhooks if w["type"] == "project"]
username, wid = next(
(
(user["username"], webhook["id"])
for user in users
for webhook in proj_webhooks
if privilege in user["groups"]
and projects[webhook["project_id"]]["owner"]["id"] != user["id"]
and webhook["owner"]["id"] != user["id"]
)
)
response = get_method(username, f"webhooks/{wid}")
assert response.status_code == HTTPStatus.FORBIDDEN
@pytest.mark.parametrize("role", ["owner", "maintainer"])
def test_org_staff_can_see_org_webhook(self, role, webhooks, find_users):
webhook = next((w for w in webhooks if w["type"] == "organization"))
username = next((u["username"] for u in find_users(role=role, org=webhook["organization"])))
response = get_method(username, f"webhooks/{webhook['id']}", org_id=webhook["organization"])
assert response.status_code == HTTPStatus.OK
assert "secret" not in response.json()
assert DeepDiff(webhook, response.json(), ignore_order=True) == {}
@pytest.mark.parametrize("role", ["owner", "maintainer"])
def test_org_staff_can_see_project_webhook_in_org(self, role, webhooks, find_users, projects):
proj_webhooks = [
w for w in webhooks if w["organization"] is not None and w["type"] == "project"
]
username, webhook = next(
(
(user["username"], webhook)
for webhook in proj_webhooks
for user in find_users(role=role, org=webhook["organization"])
if projects[webhook["project_id"]]["owner"]["id"] != user["id"]
and webhook["owner"]["id"] != user["id"]
)
)
response = get_method(username, f"webhooks/{webhook['id']}", org_id=webhook["organization"])
assert response.status_code == HTTPStatus.OK
assert "secret" not in response.json()
assert DeepDiff(webhook, response.json(), ignore_order=True) == {}
@pytest.mark.parametrize("role", ["worker", "supervisor"])
def test_member_cannot_get_org_webhook(self, role, webhooks, find_users):
webhook = next((w for w in webhooks if w["type"] == "organization"))
username = next((u["username"] for u in find_users(role=role, org=webhook["organization"])))
response = get_method(username, f"webhooks/{webhook['id']}", org_id=webhook["organization"])
assert response.status_code == HTTPStatus.FORBIDDEN
@pytest.mark.parametrize("role", ["worker", "supervisor"])
def test_member_cannot_get_project_webhook_in_org(self, role, webhooks, find_users, projects):
proj_webhooks = [
w for w in webhooks if w["organization"] is not None and w["type"] == "project"
]
username, webhook = next(
(
(user["username"], webhook)
for webhook in proj_webhooks
for user in find_users(role=role, org=webhook["organization"])
if projects[webhook["project_id"]]["owner"]["id"] != user["id"]
and webhook["owner"]["id"] != user["id"]
)
)
response = get_method(username, f"webhooks/{webhook['id']}", org_id=webhook["organization"])
assert response.status_code == HTTPStatus.FORBIDDEN
@pytest.mark.parametrize("role", ["supervisor"])
def test_member_can_get_project_webhook_in_org(self, role, webhooks, find_users, projects):
proj_webhooks = [
w for w in webhooks if w["organization"] is not None and w["type"] == "project"
]
username, webhook = next(
(
(user["username"], webhook)
for webhook in proj_webhooks
for user in find_users(role=role, org=webhook["organization"])
if projects[webhook["project_id"]]["owner"]["id"] == user["id"]
or webhook["owner"]["id"] == user["id"]
)
)
response = get_method(username, f"webhooks/{webhook['id']}", org_id=webhook["organization"])
assert response.status_code == HTTPStatus.OK
assert "secret" not in response.json()
assert DeepDiff(webhook, response.json(), ignore_order=True) == {}
class TestWebhooksListFilters(CollectionSimpleFilterTestBase):
field_lookups = {
"owner": ["owner", "username"],
}
@pytest.fixture(autouse=True)
def setup(self, restore_db_per_class, admin_user, webhooks):
self.user = admin_user
self.samples = webhooks
def _get_endpoint(self, api_client: ApiClient) -> Endpoint:
return api_client.webhooks_api.list_endpoint
@pytest.mark.parametrize(
"field",
("target_url", "owner", "type", "project_id"),
)
def test_can_use_simple_filter_for_object_list(self, field):
return super().test_can_use_simple_filter_for_object_list(field)
@pytest.mark.usefixtures("restore_db_per_class")
class TestGetListWebhooks:
def test_can_get_webhooks_list(self, webhooks):
response = get_method("admin2", "webhooks")
assert response.status_code == HTTPStatus.OK
assert all(["secret" not in webhook for webhook in response.json()["results"]])
assert DeepDiff(webhooks.raw, response.json()["results"], ignore_order=True) == {}
def test_admin_can_get_webhooks_for_project(self, webhooks):
pid = next(
(
webhook["project_id"]
for webhook in webhooks
if webhook["type"] == "project" and webhook["organization"] is None
)
)
expected_response = [
webhook
for webhook in webhooks
if webhook["type"] == "project" and webhook["project_id"] == pid
]
filter_val = '{"and":[{"==":[{"var":"project_id"},%s]}]}' % pid
response = get_method("admin2", "webhooks", filter=filter_val)
assert response.status_code == HTTPStatus.OK
assert DeepDiff(expected_response, response.json()["results"], ignore_order=True) == {}
def test_admin_can_get_webhooks_for_organization(self, webhooks):
org_id = next(
(webhook["organization"] for webhook in webhooks if webhook["organization"] is not None)
)
expected_response = [webhook for webhook in webhooks if webhook["organization"] == org_id]
response = get_method("admin2", "webhooks", org_id=org_id)
assert response.status_code == HTTPStatus.OK
assert DeepDiff(expected_response, response.json()["results"], ignore_order=True) == {}
def test_admin_can_get_webhooks_for_project_in_org(self, webhooks):
pid, oid = next(
(
(webhook["project_id"], webhook["organization"])
for webhook in webhooks
if webhook["type"] == "project" and webhook["organization"] is not None
)
)
expected_response = [
webhook
for webhook in webhooks
if webhook["project_id"] == pid and webhook["organization"] == oid
]
filter_val = '{"and":[{"==":[{"var":"project_id"},%s]}]}' % pid
response = get_method("admin2", "webhooks", org_id=oid, filter=filter_val)
assert response.status_code == HTTPStatus.OK
assert DeepDiff(expected_response, response.json()["results"], ignore_order=True) == {}
@pytest.mark.parametrize("privilege", ["user", "business"])
def test_user_cannot_get_webhook_list_for_project(
self, privilege, find_users, webhooks, projects
):
username, pid = next(
(
(user["username"], webhook["project_id"])
for user in find_users(privilege=privilege)
for webhook in webhooks
if webhook["type"] == "project"
and webhook["organization"] is None
and webhook["owner"]["id"] != user["id"]
and projects[webhook["project_id"]]["owner"]["id"] != user["id"]
)
)
filter_val = '{"and":[{"==":[{"var":"project_id"},%s]}]}' % pid
response = get_method(username, "webhooks", filter=filter_val)
assert response.status_code == HTTPStatus.OK
assert DeepDiff([], response.json()["results"], ignore_order=True) == {}
@pytest.mark.parametrize("privilege", ["user", "business"])
def test_user_can_get_webhook_list_for_project(self, privilege, find_users, webhooks, projects):
username, pid = next(
(
(user["username"], webhook["project_id"])
for user in find_users(privilege=privilege)
for webhook in webhooks
if webhook["type"] == "project"
and webhook["organization"] is None
and projects[webhook["project_id"]]["owner"]["id"] == user["id"]
)
)
expected_response = [
w for w in webhooks if w["type"] == "project" and w["project_id"] == pid
]
filter_val = '{"and":[{"==":[{"var":"project_id"},%s]}]}' % pid
response = get_method(username, "webhooks", filter=filter_val)
assert response.status_code == HTTPStatus.OK
assert DeepDiff(expected_response, response.json()["results"], ignore_order=True) == {}
def test_non_member_cannot_see_webhook_list_for_org(self, webhooks, users, is_org_member):
username, org_id = next(
(
(user["username"], webhook["organization"])
for webhook in webhooks
for user in users
if webhook["organization"] is not None
and not is_org_member(user["id"], webhook["organization"])
and "admin" not in user["groups"]
)
)
response = get_method(username, "webhooks", org_id=org_id)
assert response.status_code == HTTPStatus.FORBIDDEN
@pytest.mark.parametrize("role", ["maintainer", "owner"])
def test_org_staff_can_see_all_org_webhooks(self, role, webhooks, organizations, find_users):
username, org_id = next(
(
(user["username"], org["id"])
for webhook in webhooks
for org in organizations
for user in find_users(role=role, org=org["id"])
if webhook["organization"] == org["id"]
)
)
expected_response = [webhook for webhook in webhooks if webhook["organization"] == org_id]
response = get_method(username, "webhooks", org_id=org_id)
assert response.status_code == HTTPStatus.OK
assert DeepDiff(expected_response, response.json()["results"], ignore_order=True) == {}
@pytest.mark.parametrize("role", ["worker", "supervisor"])
def test_member_cannot_see_all_org_webhook(
self, role, webhooks, organizations, find_users, projects
):
username, org_id = next(
(
(user["username"], org["id"])
for webhook in webhooks
for org in organizations
for user in find_users(role=role, org=org["id"])
if webhook["organization"] == org["id"]
)
)
expected_response = [
webhook
for webhook in webhooks
if webhook["organization"] == org_id
and (
webhook["owner"]["username"] == username
or (
webhook["project_id"]
and projects[webhook["project_id"]]["owner"]["username"] == username
)
)
]
response = get_method(username, "webhooks", org_id=org_id)
assert response.status_code == HTTPStatus.OK
assert DeepDiff(expected_response, response.json()["results"], ignore_order=True) == {}
@pytest.mark.parametrize("role", ["supervisor"])
def test_member_can_see_list_of_project_webhooks_in_org(
self, role, webhooks, organizations, find_users, projects
):
username, org_id = next(
(
(user["username"], org["id"])
for webhook in webhooks
for org in organizations
for user in find_users(role=role, org=org["id"])
if webhook["organization"] == org["id"]
and webhook["type"] == "project"
and projects[webhook["project_id"]]["owner"]["id"] == user["id"]
)
)
expected_response = [
webhook
for webhook in webhooks
if webhook["organization"] == org_id
and webhook["type"] == "project"
and projects[webhook["project_id"]]["owner"]["username"] == username
]
response = get_method(username, "webhooks", org_id=org_id)
assert response.status_code == HTTPStatus.OK
assert DeepDiff(expected_response, response.json()["results"], ignore_order=True) == {}
@pytest.mark.parametrize("field_value, query_value", [(1, 1), (None, "")])
def test_can_filter_by_org_id(self, field_value, query_value, webhooks):
webhooks = filter(lambda w: w["organization"] == field_value, webhooks)
response = get_method("admin2", f"webhooks", org_id=query_value)
assert response.status_code == HTTPStatus.OK
assert DeepDiff(list(webhooks), response.json()["results"], ignore_order=True) == {}
@pytest.mark.usefixtures("restore_db_per_function")
class TestPatchWebhooks:
WID = 2
def test_sandbox_admin_can_update_any_webhook(self, webhooks, find_users):
username, webhook = next(
(
(user["username"], deepcopy(webhook))
for user in find_users(privilege="admin")
for webhook in webhooks
if webhook["owner"]["id"] != user["id"] and webhook["organization"] is None
)
)
patch_data = {
"target_url": "http://newexample.com",
"secret": "newsecret",
"events": ["create:task"],
"is_active": not webhook["is_active"],
"enable_ssl": not webhook["enable_ssl"],
}
webhook.update(patch_data)
response = patch_method(username, f"webhooks/{webhook['id']}", patch_data)
assert response.status_code == HTTPStatus.OK
assert "secret" not in response.json()
assert (
DeepDiff(
webhook,
response.json(),
ignore_order=True,
exclude_paths=["root['updated_date']", "root['secret']"],
)
== {}
)
def test_cannot_update_with_nonexistent_contenttype(self):
patch_data = {"content_type": "application/x-www-form-urlencoded"}
response = patch_method("admin2", f"webhooks/{self.WID}", patch_data)
assert response.status_code == HTTPStatus.BAD_REQUEST
@pytest.mark.parametrize("privilege", ["user", "business"])
def test_sandbox_user_can_update_webhook(self, privilege, find_users, webhooks):
username, webhook = next(
(
(user["username"], deepcopy(webhook))
for user in find_users(privilege=privilege)
for webhook in webhooks
if webhook["owner"]["id"] == user["id"]
)
)
patch_data = {"target_url": "http://newexample.com"}
webhook.update(patch_data)
response = patch_method(username, f"webhooks/{webhook['id']}", patch_data)
assert response.status_code == HTTPStatus.OK
assert "secret" not in response.json()
assert (
DeepDiff(
webhook,
response.json(),
ignore_order=True,
exclude_paths=["root['updated_date']", "root['secret']"],
)
== {}
)
@pytest.mark.parametrize("privilege", ["worker", "user", "business"])
def test_sandbox_user_cannot_update_webhook(self, privilege, find_users, webhooks):
username, webhook = next(
(
(user["username"], deepcopy(webhook))
for user in find_users(privilege=privilege)
for webhook in webhooks
if webhook["owner"]["id"] != user["id"]
)
)
patch_data = {"target_url": "http://newexample.com"}
webhook.update(patch_data)
response = patch_method(username, f"webhooks/{webhook['id']}", patch_data)
assert response.status_code == HTTPStatus.FORBIDDEN
def test_admin_can_update_org_webhook(self, find_users, organizations, webhooks, is_org_member):
org_webhooks = [w for w in webhooks if w["type"] == "organization"]
admin, oid, webhook = next(
(
(u["username"], o["id"], deepcopy(w))
for u in find_users(privilege="admin")
for o in organizations
for w in org_webhooks
if w["organization"] == o["id"] and not is_org_member(u["id"], o["id"])
)
)
patch_data = {"target_url": "http://newexample.com"}
webhook.update(patch_data)
response = patch_method(admin, f"webhooks/{webhook['id']}", patch_data, org_id=oid)
assert response.status_code == HTTPStatus.OK
assert "secret" not in response.json()
assert (
DeepDiff(
webhook,
response.json(),
ignore_order=True,
exclude_paths=["root['updated_date']", "root['secret']"],
)
== {}
)
@pytest.mark.parametrize("role", ["maintainer", "owner"])
def test_member_can_update_org_webhook(self, role, find_users, organizations, webhooks):
org_webhooks = [w for w in webhooks if w["type"] == "organization"]
username, oid, webhook = next(
(
(u["username"], o["id"], deepcopy(w))
for o in organizations
for u in find_users(role=role, org=o["id"])
for w in org_webhooks
if w["organization"] == o["id"]
)
)
patch_data = {"target_url": "http://newexample.com"}
webhook.update(patch_data)
response = patch_method(username, f"webhooks/{webhook['id']}", patch_data, org_id=oid)
assert response.status_code == HTTPStatus.OK
assert "secret" not in response.json()
assert (
DeepDiff(
webhook,
response.json(),
ignore_order=True,
exclude_paths=["root['updated_date']", "root['secret']"],
)
== {}
)
@pytest.mark.parametrize("role", ["worker", "supervisor"])
def test_member_cannot_update_org_webhook(self, role, find_users, organizations, webhooks):
org_webhooks = [w for w in webhooks if w["type"] == "organization"]
username, oid, webhook = next(
(
(u["username"], o["id"], deepcopy(w))
for o in organizations
for u in find_users(role=role, org=o["id"])
for w in org_webhooks
if w["organization"] == o["id"]
)
)
patch_data = {"target_url": "http://newexample.com"}
webhook.update(patch_data)
response = patch_method(username, f"webhooks/{webhook['id']}", patch_data, org_id=oid)
assert response.status_code == HTTPStatus.FORBIDDEN
@pytest.mark.parametrize(
"role, allow",
[("maintainer", True), ("owner", True), ("supervisor", False), ("worker", False)],
)
def test_member_can_update_any_project_webhook_in_org(
self, role, allow, find_users, organizations, projects_by_org, webhooks, is_project_staff
):
proj_webhooks = [w for w in webhooks if w["type"] == "project"]
username, org_id, webhook = next(
(
(u["username"], o["id"], deepcopy(w))
for o in organizations
for u in find_users(role=role, org=o["id"])
for w in proj_webhooks
for p in projects_by_org.get(o["id"], [])
if w["project_id"] == p["id"]
and w["organization"] == o["id"]
and not is_project_staff(u["id"], p["id"])
and w["owner"]["id"] != u["id"]
)
)
patch_data = {"target_url": "http://newexample.com"}
webhook.update(patch_data)
response = patch_method(username, f"webhooks/{webhook['id']}", patch_data, org_id=org_id)
if not allow:
assert response.status_code == HTTPStatus.FORBIDDEN
else:
assert response.status_code == HTTPStatus.OK
assert "secret" not in response.json()
assert (
DeepDiff(
webhook,
response.json(),
ignore_order=True,
exclude_paths=["root['updated_date']", "root['secret']"],
)
== {}
)
@pytest.mark.parametrize("role", ["supervisor"])
def test_member_can_update_project_webhook_in_org(
self, role, find_users, organizations, projects_by_org, webhooks
):
proj_webhooks = [w for w in webhooks if w["type"] == "project"]
username, org_id, webhook = next(
(
(u["username"], o["id"], deepcopy(w))
for o in organizations
for u in find_users(role=role, org=o["id"])
for w in proj_webhooks
for p in projects_by_org.get(o["id"], [])
if w["project_id"] == p["id"]
and w["organization"] == o["id"]
and u["id"] == p["owner"]["id"]
)
)
patch_data = {"target_url": "http://newexample.com"}
webhook.update(patch_data)
response = patch_method(username, f"webhooks/{webhook['id']}", patch_data, org_id=org_id)
assert response.status_code == HTTPStatus.OK
assert "secret" not in response.json()
assert (
DeepDiff(
webhook,
response.json(),
ignore_order=True,
exclude_paths=["root['updated_date']", "root['secret']"],
)
== {}
)
@pytest.mark.usefixtures("restore_db_per_function")
class TestDeleteWebhooks:
@pytest.mark.parametrize(
"privilege, allow", [("user", False), ("business", False), ("admin", True)]
)
def test_user_can_delete_project_webhook(
self, privilege, allow, find_users, webhooks, projects
):
users = find_users(privilege=privilege)
username, webhook_id = next(
(
(user["username"], webhook["id"])
for webhook in webhooks
for user in users
if webhook["type"] == "project"
and webhook["organization"] is None
and webhook["owner"]["id"] != user["id"]
and projects[webhook["project_id"]]["owner"]["id"] != user["id"]
)
)
if not allow:
response = delete_method(username, f"webhooks/{webhook_id}")
assert response.status_code == HTTPStatus.FORBIDDEN
else:
response = delete_method(username, f"webhooks/{webhook_id}")
assert response.status_code == HTTPStatus.NO_CONTENT
response = get_method(username, f"webhooks/{webhook_id}")
assert response.status_code == HTTPStatus.NOT_FOUND
def test_admin_can_delete_project_webhook_in_org(
self, find_users, webhooks, projects, is_org_member
):
admins = find_users(privilege="admin")
username, webhook_id = next(
(
(user["username"], webhook["id"])
for user in admins
for webhook in webhooks
if webhook["type"] == "project"
and webhook["organization"] is not None
and webhook["owner"]["id"] != user["id"]
and projects[webhook["project_id"]]["owner"]["id"] != user["id"]
and not is_org_member(user["id"], webhook["organization"])
)
)
response = delete_method(username, f"webhooks/{webhook_id}")
assert response.status_code == HTTPStatus.NO_CONTENT
response = get_method(username, f"webhooks/{webhook_id}")
assert response.status_code == HTTPStatus.NOT_FOUND
def test_admin_can_delete_org_webhook(self, find_users, webhooks, is_org_member):
admins = find_users(privilege="admin")
username, webhook_id = next(
(
(user["username"], webhook["id"])
for user in admins
for webhook in webhooks
if webhook["type"] == "organization"
and webhook["organization"] is not None
and webhook["owner"]["id"] != user["id"]
and not is_org_member(user["id"], webhook["organization"])
)
)
response = delete_method(username, f"webhooks/{webhook_id}")
assert response.status_code == HTTPStatus.NO_CONTENT
response = get_method(username, f"webhooks/{webhook_id}")
assert response.status_code == HTTPStatus.NOT_FOUND
@pytest.mark.parametrize("privilege", ["user", "business"])
def test_project_owner_can_delete_project_webhook(
self, privilege, find_users, webhooks, projects
):
users = find_users(privilege=privilege)
username, webhook_id = next(
(
(user["username"], webhook["id"])
for user in users
for webhook in webhooks
if webhook["type"] == "project"
and webhook["organization"] is None
and projects[webhook["project_id"]]["owner"]["id"] == user["id"]
)
)
response = delete_method(username, f"webhooks/{webhook_id}")
assert response.status_code == HTTPStatus.NO_CONTENT
response = get_method(username, f"webhooks/{webhook_id}")
assert response.status_code == HTTPStatus.NOT_FOUND
@pytest.mark.parametrize("privilege", ["user", "business"])
def test_webhook_owner_can_delete_project_webhook(
self, privilege, find_users, webhooks, projects
):
users = find_users(privilege=privilege)
username, webhook_id = next(
(
(user["username"], webhook["id"])
for user in users
for webhook in webhooks
if webhook["type"] == "project"
and webhook["organization"] is None
and webhook["owner"]["id"] == user["id"]
)
)
response = delete_method(username, f"webhooks/{webhook_id}")
assert response.status_code == HTTPStatus.NO_CONTENT
response = get_method(username, f"webhooks/{webhook_id}")
assert response.status_code == HTTPStatus.NOT_FOUND
@pytest.mark.parametrize(
"role, allow",
[("owner", True), ("maintainer", True), ("worker", False), ("supervisor", False)],
)
def test_member_can_delete_org_webhook(self, role, allow, find_users, organizations, webhooks):
org_webhooks = [w for w in webhooks if w["type"] == "organization"]
username, org_id, webhook_id = next(
(
(user["username"], org["id"], webhook["id"])
for org in organizations
for webhook in org_webhooks
for user in find_users(role=role, org=org["id"])
if webhook["organization"] == org["id"]
)
)
if not allow:
response = delete_method(username, f"webhooks/{webhook_id}", org_id=org_id)
assert response.status_code == HTTPStatus.FORBIDDEN
else:
response = delete_method(username, f"webhooks/{webhook_id}", org_id=org_id)
assert response.status_code == HTTPStatus.NO_CONTENT
response = get_method(username, f"webhooks/{webhook_id}", org_id=org_id)
assert response.status_code == HTTPStatus.NOT_FOUND
@pytest.mark.parametrize(
"role, allow",
[("owner", True), ("maintainer", True), ("worker", False), ("supervisor", False)],
)
def test_member_can_delete_project_webhook_in_org(
self, role, allow, find_users, organizations, projects, webhooks
):
proj_webhooks = [w for w in webhooks if w["type"] == "project"]
username, org_id, webhook_id = next(
(
(user["username"], webhook["organization"], webhook["id"])
for org in organizations
for user in find_users(role=role, org=org["id"])
for webhook in proj_webhooks
if webhook["organization"]
and webhook["organization"] == org["id"]
and projects[webhook["project_id"]]["owner"]["id"] != user["id"]
and webhook["owner"]["id"] != user["id"]
)
)
if not allow:
response = delete_method(username, f"webhooks/{webhook_id}", org_id=org_id)
assert response.status_code == HTTPStatus.FORBIDDEN
else:
response = delete_method(username, f"webhooks/{webhook_id}", org_id=org_id)
assert response.status_code == HTTPStatus.NO_CONTENT
response = get_method(username, f"webhooks/{webhook_id}", org_id=org_id)
assert response.status_code == HTTPStatus.NOT_FOUND
@pytest.mark.parametrize("role", ["supervisor"])
def test_member_webhook_staff_can_delete_project_webhook_in_org(
self, role, find_users, organizations, projects, webhooks
):
proj_webhooks = [w for w in webhooks if w["type"] == "project"]
username, org_id, webhook_id = next(
(
(user["username"], webhook["organization"], webhook["id"])
for org in organizations
for user in find_users(role=role, org=org["id"])
for webhook in proj_webhooks
if webhook["organization"]
and webhook["organization"] == org["id"]
and (
projects[webhook["project_id"]]["owner"]["id"] == user["id"]
or webhook["owner"]["id"] == user["id"]
)
)
)
response = delete_method(username, f"webhooks/{webhook_id}", org_id=org_id)
assert response.status_code == HTTPStatus.NO_CONTENT
response = get_method(username, f"webhooks/{webhook_id}", org_id=org_id)
assert response.status_code == HTTPStatus.NOT_FOUND
Computing file changes ...