From e025d8c2b28492fd9b25748c20f5f8b31c05f01a Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Mon, 13 Feb 2017 18:04:41 -0500 Subject: [PATCH] Add schema validation of namespaces and sources methods --- buildtrigger/basehandler.py | 84 ++++++++++++++++++++++++ buildtrigger/bitbuckethandler.py | 5 +- buildtrigger/githubhandler.py | 8 ++- buildtrigger/gitlabhandler.py | 5 +- buildtrigger/test/test_githosthandler.py | 3 +- 5 files changed, 96 insertions(+), 9 deletions(-) diff --git a/buildtrigger/basehandler.py b/buildtrigger/basehandler.py index b9f035dc0..f8ed97563 100644 --- a/buildtrigger/basehandler.py +++ b/buildtrigger/basehandler.py @@ -6,6 +6,79 @@ from endpoints.building import PreparedBuild from data import model from buildtrigger.triggerutil import get_trigger_config, InvalidServiceException +NAMESPACES_SCHEMA = { + 'type': 'array', + 'items': { + 'type': 'object', + 'properties': { + 'personal': { + 'type': 'boolean', + 'description': 'True if the namespace is the user\'s personal namespace', + }, + 'score': { + 'type': 'number', + 'description': 'Score of the relevance of the namespace', + }, + 'avatar_url': { + 'type': 'string', + 'description': 'URL of the avatar for this namespace', + }, + 'url': { + 'type': 'string', + 'description': 'URL of the website to view the namespace', + }, + 'id': { + 'type': 'string', + 'description': 'Trigger-internal ID of the namespace', + }, + 'title': { + 'type': 'string', + 'description': 'Human-readable title of the namespace', + }, + }, + 'required': ['personal', 'score', 'avatar_url', 'url', 'id', 'title'], + }, +} + +BUILD_SOURCES_SCHEMA = { + 'type': 'array', + 'items': { + 'type': 'object', + 'properties': { + 'name': { + 'type': 'string', + 'description': 'The name of the repository, without its namespace', + }, + 'full_name': { + 'type': 'string', + 'description': 'The name of the repository, with its namespace', + }, + 'description': { + 'type': 'string', + 'description': 'The description of the repository. May be an empty string', + }, + 'last_updated': { + 'type': 'number', + 'description': 'The date/time when the repository was last updated, since epoch in UTC', + }, + 'url': { + 'type': 'string', + 'description': 'The URL at which to view the repository in the browser', + }, + 'has_admin_permissions': { + 'type': 'boolean', + 'description': 'True if the current user has admin permissions on the repository', + }, + 'private': { + 'type': 'boolean', + 'description': 'True if the repository is private', + }, + }, + 'required': ['name', 'full_name', 'description', 'last_updated', 'url', + 'has_admin_permissions', 'private'], + }, +} + METADATA_SCHEMA = { 'type': 'object', 'properties': { @@ -242,3 +315,14 @@ class BuildTriggerHandler(object): prepared.tags = [commit_sha[:7]] return prepared + + @classmethod + def build_sources_response(cls, sources): + validate(sources, BUILD_SOURCES_SCHEMA) + return sources + + @classmethod + def build_namespaces_response(cls, namespaces_dict): + namespaces = list(namespaces_dict.values()) + validate(namespaces, NAMESPACES_SCHEMA) + return namespaces diff --git a/buildtrigger/bitbuckethandler.py b/buildtrigger/bitbuckethandler.py index 2f26626a9..02e6b228f 100644 --- a/buildtrigger/bitbuckethandler.py +++ b/buildtrigger/bitbuckethandler.py @@ -416,7 +416,7 @@ class BitbucketBuildTrigger(BuildTriggerHandler): 'score': 1, } - return list(namespaces.values()) + return BuildTriggerHandler.build_namespaces_response(namespaces) def list_build_sources_for_namespace(self, namespace): def repo_view(repo): @@ -437,7 +437,8 @@ class BitbucketBuildTrigger(BuildTriggerHandler): if not result: raise RepositoryReadException('Could not read repository list: ' + err_msg) - return [repo_view(repo) for repo in data if repo['owner'] == namespace] + repos = [repo_view(repo) for repo in data if repo['owner'] == namespace] + return BuildTriggerHandler.build_sources_response(repos) def list_build_subdirs(self): config = self.config diff --git a/buildtrigger/githubhandler.py b/buildtrigger/githubhandler.py index 3233f5f5d..b7eca92cc 100644 --- a/buildtrigger/githubhandler.py +++ b/buildtrigger/githubhandler.py @@ -300,7 +300,7 @@ class GithubBuildTrigger(BuildTriggerHandler): 'score': org.plan.private_repos if org.plan else 0, } - return list(namespaces.values()) + return BuildTriggerHandler.build_namespaces_response(namespaces) @_catch_ssl_errors def list_build_sources_for_namespace(self, namespace): @@ -318,7 +318,8 @@ class GithubBuildTrigger(BuildTriggerHandler): gh_client = self._get_client() usr = gh_client.get_user() if namespace == usr.login: - return [repo_view(repo) for repo in usr.get_repos() if repo.owner.login == namespace] + repos = [repo_view(repo) for repo in usr.get_repos() if repo.owner.login == namespace] + return BuildTriggerHandler.build_sources_response(repos) try: org = gh_client.get_organization(namespace) @@ -327,7 +328,8 @@ class GithubBuildTrigger(BuildTriggerHandler): except GithubException: return [] - return [repo_view(repo) for repo in org.get_repos(type='member')] + repos = [repo_view(repo) for repo in org.get_repos(type='member')] + return BuildTriggerHandler.build_sources_response(repos) @_catch_ssl_errors diff --git a/buildtrigger/gitlabhandler.py b/buildtrigger/gitlabhandler.py index 90be9f698..5d221874b 100644 --- a/buildtrigger/gitlabhandler.py +++ b/buildtrigger/gitlabhandler.py @@ -289,7 +289,7 @@ class GitLabBuildTrigger(BuildTriggerHandler): 'url': gl_client.host + '/' + namespace['path'], } - return list(namespaces.values()) + return BuildTriggerHandler.build_namespaces_response(namespaces) @_catch_timeouts def list_build_sources_for_namespace(self, namespace): @@ -313,7 +313,8 @@ class GitLabBuildTrigger(BuildTriggerHandler): gl_client = self._get_authorized_client() repositories = _paginated_iterator(gl_client.getprojects, RepositoryReadException) - return [repo_view(repo) for repo in repositories if repo['namespace']['path'] == namespace] + repos = [repo_view(repo) for repo in repositories if repo['namespace']['path'] == namespace] + return BuildTriggerHandler.build_sources_response(repos) @_catch_timeouts def list_build_subdirs(self): diff --git a/buildtrigger/test/test_githosthandler.py b/buildtrigger/test/test_githosthandler.py index 2cf4f9175..06e73578d 100644 --- a/buildtrigger/test/test_githosthandler.py +++ b/buildtrigger/test/test_githosthandler.py @@ -108,12 +108,11 @@ def test_list_build_source_namespaces(githost_trigger): }]), ]) def test_list_build_sources_for_namespace(namespace, expected, githost_trigger): - # TODO: schema validation on the resulting namespaces. assert githost_trigger.list_build_sources_for_namespace(namespace) == expected def test_activate(githost_trigger): - config, private_key = githost_trigger.activate('http://some/url') + _, private_key = githost_trigger.activate('http://some/url') assert 'private_key' in private_key