diff --git a/master/buildbot/newsfragments/endpointmatchers.feature b/master/buildbot/newsfragments/endpointmatchers.feature new file mode 100644 index 00000000000..752daa15656 --- /dev/null +++ b/master/buildbot/newsfragments/endpointmatchers.feature @@ -0,0 +1 @@ +Added :py:class:`AnyControlEndpointMatcher` and :py:class:`EnableSchedulerEndpointMatcher` for better configurability of the access control. If you have access control to your Buildbot, it is recommended you add :py:class:`AnyControlEndpointMatcher` at the end of your access control configuration. diff --git a/master/buildbot/test/unit/test_www_endpointmatchers.py b/master/buildbot/test/unit/test_www_endpointmatchers.py index 37636d88577..d2074badc78 100644 --- a/master/buildbot/test/unit/test_www_endpointmatchers.py +++ b/master/buildbot/test/unit/test_www_endpointmatchers.py @@ -25,13 +25,6 @@ from buildbot.www.authz import endpointmatchers -# AnyEndpointMatcher -# ForceBuildEndpointMatcher -# BranchEndpointMatcher -# ViewBuildsEndpointMatcher -# StopBuildEndpointMatcher - - class EndpointBase(www.WwwTestMixin, unittest.TestCase): def setUp(self): @@ -81,6 +74,22 @@ def test_nominal(self): self.assertMatch(ret) +class AnyControlEndpointMatcher(EndpointBase): + + def makeMatcher(self): + return endpointmatchers.AnyControlEndpointMatcher(role="foo") + + @defer.inlineCallbacks + def test_get(self): + ret = yield self.matcher.match(("foo", "bar")) + self.assertNotMatch(ret) + + @defer.inlineCallbacks + def test_other_action(self): + ret = yield self.matcher.match(("foo", "bar"), action="foo") + self.assertMatch(ret) + + class ViewBuildsEndpointMatcherBranch(EndpointBase, ValidEndpointMixin): def makeMatcher(self): @@ -89,7 +98,8 @@ def makeMatcher(self): @defer.inlineCallbacks def test_build(self): ret = yield self.matcher.match(("builds", "15")) - self.assertNotMatch(ret) + self.assertMatch(ret) + test_build.skip = "ViewBuildsEndpointMatcher is not implemented yet" class StopBuildEndpointMatcherBranch(EndpointBase, ValidEndpointMixin): @@ -151,3 +161,19 @@ def test_forcesched_nobuilder(self): self.matcher.builder = None ret = yield self.matcher.match(("forceschedulers", "sched1"), "force") self.assertMatch(ret) + + +class EnableSchedulerEndpointMatcher(EndpointBase, ValidEndpointMixin): + + def makeMatcher(self): + return endpointmatchers.EnableSchedulerEndpointMatcher(role="agent") + + @defer.inlineCallbacks + def test_build(self): + ret = yield self.matcher.match(("builds", "15"), "stop") + self.assertNotMatch(ret) + + @defer.inlineCallbacks + def test_scheduler_enable(self): + ret = yield self.matcher.match(("schedulers", "15"), "enable") + self.assertMatch(ret) diff --git a/master/buildbot/www/authz/endpointmatchers.py b/master/buildbot/www/authz/endpointmatchers.py index a620cb13529..08b1f8a1dc1 100644 --- a/master/buildbot/www/authz/endpointmatchers.py +++ b/master/buildbot/www/authz/endpointmatchers.py @@ -104,6 +104,17 @@ def match(self, ep, action="get", options=None): return defer.succeed(Match(self.master)) +class AnyControlEndpointMatcher(EndpointMatcherBase): + + def __init__(self, **kwargs): + EndpointMatcherBase.__init__(self, **kwargs) + + def match(self, ep, action="get", options=None): + if action != "get": + return defer.succeed(Match(self.master)) + return defer.succeed(None) + + class StopBuildEndpointMatcher(EndpointMatcherBase): def __init__(self, builder=None, **kwargs): @@ -177,6 +188,12 @@ def match_BuildEndpoint_rebuild(self, epobject, epdict, options): build = yield epobject.get({}, epdict) defer.returnValue(Match(self.master, build=build)) + +class EnableSchedulerEndpointMatcher(EndpointMatcherBase): + + def match_SchedulerEndpoint_enable(self, epobject, epdict, options): + return defer.succeed(Match(self.master)) + ##### # not yet implemented diff --git a/master/docs/manual/cfg-www.rst b/master/docs/manual/cfg-www.rst index 14e2052c2bf..1656abb7cee 100644 --- a/master/docs/manual/cfg-www.rst +++ b/master/docs/manual/cfg-www.rst @@ -605,28 +605,43 @@ In this case, you can look at the source code for detailed examples on how to wr :param role: The role which grants access to any endpoint. - AnyEndpointMatcher grants all rights to a people with given role (usually "admins") + AnyEndpointMatcher grants all rights to people with given role (usually "admins") + +.. py:class:: buildbot.www.authz.endpointmatchers.AnyControlEndpointMatcher(role) + + :param role: The role which grants access to any control endpoint. + + AnyControlEndpointMatcher grants control rights to people with given role (usually "admins") + This endpoint matcher is matches current and future control endpoints. + You need to add this in the end of your configuration to make sure it is future proof. .. py:class:: buildbot.www.authz.endpointmatchers.ForceBuildEndpointMatcher(builder, role) :param builder: name of the builder. :param role: The role needed to get access to such endpoints. - ForceBuildEndpointMatcher grants all rights to a people with given role (usually "admins") + ForceBuildEndpointMatcher grants right to force builds. .. py:class:: buildbot.www.authz.endpointmatchers.StopBuildEndpointMatcher(builder, role) :param builder: name of the builder. :param role: The role needed to get access to such endpoints. - StopBuildEndpointMatcher grants all rights to a people with given role (usually "admins") + StopBuildEndpointMatcher grants rights to stop builds. .. py:class:: buildbot.www.authz.endpointmatchers.RebuildBuildEndpointMatcher(builder, role) :param builder: name of the builder. :param role: The role needed to get access to such endpoints. - RebuildBuildEndpointMatcher grants all rights to a people with given role (usually "admins") + RebuildBuildEndpointMatcher grants rights to rebuild builds. + +.. py:class:: buildbot.www.authz.endpointmatchers.EnableSchedulerEndpointMatcher(builder, role) + + :param builder: name of the builder. + :param role: The role needed to get access to such endpoints. + + EnableSchedulerEndpointMatcher grants rights to enable and disable schedulers via the UI. Role matchers +++++++++++++ @@ -689,16 +704,14 @@ You can grant roles from groups information provided by the Auth plugins, or if Example Configs +++++++++++++++ -Simple config which allows admin people to run everything: +Simple config which allows admin people to control everything, but allow anonymous to look at build results: .. code-block:: python from buildbot.plugins import * authz = util.Authz( allowRules=[ - util.StopBuildEndpointMatcher(role="admins"), - util.ForceBuildEndpointMatcher(role="admins"), - util.RebuildBuildEndpointMatcher(role="admins") + util.AnyControlEndpointMatcher(role="admins"), ], roleMatchers=[ util.RolesFromEmails(admins=["my@email.com"]) @@ -730,6 +743,8 @@ More complex config with separation per branch: util.ForceBuildEndpointMatcher(builder="merge", role="*-mergers"), # *-releasers groups can start "release" builds util.ForceBuildEndpointMatcher(builder="release", role="*-releasers"), + # if future Buildbot implement new control, we are safe with this last rule + util.AnyControlEndpointMatcher(role="admins") ], roleMatchers=[ RolesFromGroups(groupPrefix="buildbot-"), @@ -741,14 +756,14 @@ More complex config with separation per branch: ) c['www']['authz'] = authz -Using GitHub authentication and allowing access to all endpoints for users in the "BuildBot" organization: +Using GitHub authentication and allowing access to control endpoints for users in the "BuildBot" organization: .. code-block:: python from buildbot.plugins import * authz = util.Authz( allowRules=[ - util.AnyEndpointMatcher(role="BuildBot", defaultDeny=True) + util.AnyControlEndpointMatcher(role="BuildBot") ], roleMatchers=[ util.RolesFromGroups() diff --git a/master/setup.py b/master/setup.py index 044ecb5eb74..ab3d411de48 100755 --- a/master/setup.py +++ b/master/setup.py @@ -383,7 +383,7 @@ def define_plugin_entries(groups): 'RolesFromEmails', 'RolesFromGroups', 'RolesFromOwner', 'RolesFromUsername']), ('buildbot.www.authz.endpointmatchers', [ 'AnyEndpointMatcher', 'StopBuildEndpointMatcher', 'ForceBuildEndpointMatcher', - 'RebuildBuildEndpointMatcher']), + 'RebuildBuildEndpointMatcher', 'AnyComtrolEndpointMatcher', 'EnableSchedulerEndpointMatcher']), ]) ]), { 'console_scripts': [