Metadata | |
---|---|
cEP | 15 |
Version | 1.0 |
Title | corobo Enhancement (security, tests and configurability) |
Authors | Nitanshu Vashistha mailto:[email protected] |
Status | Proposed |
Type | Process |
This cEP describes the details of enhancement of corobo in terms of security, tests, configurability and the new plugins that are to be added to corobo as part of the GSoC Project.
Security has been one of the major concerns due to some past experiences. These are the changes that will be implemented to the existing plugins in order to harden the security.
-
Give developers the right to invite newcomers to the organization. This will involve changing the bot command to
corobo invite <@username>
. -
Remove the automatic invite due to
Hello World
message. -
Remove
invite me
bot command. -
Stop newcomers from getting assigned to more than one newcomer issue.
-
Make all LabHub plugins require being a member of the organization. This will be done by creating a
members_only
decorator to check if the user is a member of team or not. The decorator can be used on any bot command which needs to be under the accessibility of an organization member only.def members_only(func): @wraps(func) def wrapper(*args, **kwargs): # plugin instance instance = args[0] msg = args[1] user = msg.frm.nick for team in instance.team_mapping().values(): if team.is_member(user): yield from func(*args, **kwargs) return yield ('You need to be a member of this organization' ' to use this command.') return wrapper
-
Add callback message to warn users who are spamming the room.
-
Add bot command to ban a user from all rooms at once. The goal of this feature is to prevent spamming as someone with many accounts can't be stopped to join a room.
The default TestBase provided by Errbot is not enough for testing plugins like LabHub, which required intensive mocking.
This will involve making changes upstream in Errbot and extend the existing testing infrastructure to implement better testing for plugins like LabHub.
Errbot provides a pytest fixture testbot
for testing purposes and to interact
with the message queue. Extending the testbot and adding inject_mock
method
so that mocked objects can be injected into the plugin by passing a dictionary
containing the PluginName
, field_name
and Mocked Object
. The
inject_mock
method will inject a property on the plugin object and discard
the assignments from the plugin itself.
def test_command(testbot):
mocks = {'PluginName': {'field_name1': fakeObj1,
'field_name2': fakeObj2}}
testbot.inject_mock(mocks)
assert 'something' in testbot.exec_command('!my_command')
corobo has a potential to be used by other organizations for similar tasks like onboarding and automation. Currently, it is not configurable and many plugins are still very coala specific. Making it more configurable will allow other organizations to adapt corobo to cater their needs.
Making existing coala specific plugins generic for other organizations and letting them configure the plugins as per their needs will ensure configurability.
Errobot provides plugin configuration
through the built-in !config
command which can be used by other organizations
to configure the plugins as per their needs.
List of Plugins which are coala specific and can be generalized:
-
LabHub
plugin commands are meant to work for a coala specific team names maintainers, developers, newcomers and coala repositories.Issue Link: coala/corobo#382
-
explain
currently uses hardcoded coala explanations. Configuring sub-directoriesexplain/genric
andexplain/<org name>
so that other organizations can include their culture-specific explanations. -
searchdocs
uses API_DOCS and USER_DOCS links which are constant for coala. Other organizations will be able to initialize their own documentation links as per their requirement.Issue Link: coala/corobo#380
-
community_stats
will be moved out from LabHub as a separate plugin since it can also be used by other organizations for analytics overview.Issue Link: coala/corobo#361
-
wolfram_alpha
plugin currently uses an environment variable, it will be modified to use the configuration template.Issue Link: coala/corobo#383
-
answer
plugin useANSWER_END
environment variable as an endpoint of the answers microservice. It'll be configured so that other organizations can also adapt to it.Issue Link: coala/corobo#381
class LabHub(BotPlugin):
def get_configuration_template(self):
return {'GH_TEAM_NAMES': ['newcomers', 'developers', 'maintainers']}
@botcmd
def mycommand(self, mess, args):
# oh I need my TEAM !
gh_teams = self.config['GH_TEAM_NAMES']
<BOT_PREFIX> plugin config LabHub {'GH_TEAM_NAMES': ['newbies', 'devs', 'admins']}
Using the configuration templates means that the bot admin will have to configure the plugin every time the bot starts and since corobo is continuously deployed on each commit, reconfiguring again and again using the chat via a admin is not preferable.
This issue can be handled by using a Mixin to pre-configure the plugins through
config.py
file. By using DEFAULT_CONFIGS
in config.py
file to hold the
configuration dictionaries for the plugins. Eg:
DEFAULT_CONFIG = {
'LabHub': {
'GH_TOKEN': os.getenv('GITHUB_TOKEN'),
'GL_TOKEN': os.getenv('GITLAB_TOKEN'),
'GH_ORG_NAME': os.getenv('GH_ORG_NAME'),
},
'WolframAlpha': {
'WA_APP_ID': os.getenv('WA_TOKEN'),
},
}
Configuration of the plugins will be done before their activation and if a
plugin is already configured, the DefaultConfigMixin
will autoconfigure the
plugin from DEFAULT_CONFIGS
.
class DefaultConfigMixin:
@property
def _default_config(self) -> Optional[Mapping]:
if (self.bot_config.DEFAULT_CONFIG and self.name
in self.bot_config.DEFAULT_CONFIG):
return self.bot_config.DEFAULT_CONFIG[self.name]
def __init__(self, bot, name=None) -> None:
super().__init__(bot, name = name)
default_config = self._default_config
if default_config and not self.config:
super().configure(default_config)
def get_configuration_template(self) -> Mapping:
default_config = self._default_config
if default_config:
return default_config
class MyPlugin(BotPlugin, DefaultConfigMixin):
...
Other possible ways to configure corobo were discussed here.
Currently, most of the plugins make use of the __init__
method for instead of
activate
for configuration. Since __init__
is executed at load time its
failure will cause the plugin to not show up. Configuring the plugins through
the activate
method will remove this possibility.
Eg: labhub.py
def __init__(self, bot, name=None):
super().__init__(bot, name)
teams = dict()
try:
gh = github3.login(token=os.environ.get('GH_TOKEN'))
assert gh is not None
except AssertionError:
self.log.error('Cannot create github object, please check GH_TOKEN')
else:
self.GH3_ORG = gh.organization(self.GH_ORG_NAME)
for team in self.GH3_ORG.teams():
teams[team.name] = team
self._teams = teams
self.IGH = GitHub(GitHubToken(os.environ.get('GH_TOKEN')))
self.IGL = GitLab(GitLabPrivateToken(os.environ.get('GL_TOKEN')))
self.REPOS = dict()
def activate(self):
teams = dict()
try:
gh = github3.login(token=os.environ.get('GH_TOKEN'))
assert gh is not None
except AssertionError:
self.log.error('Cannot create github object, please check GH_TOKEN')
else:
self.GH3_ORG = gh.organization(self.GH_ORG_NAME)
for team in self.GH3_ORG.teams():
teams[team.name] = team
self._teams = teams
self.IGH = GitHub(GitHubToken(os.environ.get('GH_TOKEN')))
self.IGL = GitLab(GitLabPrivateToken(os.environ.get('GL_TOKEN')))
super(LabHub, self).activate()