Companies want to add their own features to GitLab without sharing the code with others by contributing it to the main repository (for security reasons, to iterate quickly, to have something specific to them, or to do something that doesn't meet our definition of done). Right now they have to run on a fork, that makes GitLab hard to keep up to date and we see that they tend not to upgrade.
The proposal is to:
Rename project services to plugins (to make it clear that we have plugins and because project services never was a good name)
Allow local plugins by loading them automatically if they are in a directory that is not under version control in /var/opt/gitlab/gitlab-rails/plugins
Isn't this the same thing we bash against Jenkins for?
Can all integrations be relegated to single files? I would imagine that would limit the kinds of things that can be done with this plugin architecture. e.g. modifying code diff displays to show inline static analysis results. Maybe we don't have any plugins like that today, but people will want them.
There's value in third-party contributions. There's value in curating them and protecting users from the downside of unmanaged third-party contributions. Yet there's also value in allowing companies do have private integrations. Perhaps we could make it such that local plugins are only used for private company-specific integrations while public third-party integrations use a different (curated) mechanism.
For security reasons we can't have the plugins inside of /etc/gitlab directory. This directory contains secrets, individual files and directory permissions are security tightened. We could find a better place, maybe /var/opt/gitlab/gitlab-rails/plugins. The holding directory is already accessible to unicorn and has the necessary permissions.
I wonder whether we can avoid doing it this way tough. If we depend on user adding the file, bunch of things can go wrong (think of permissions, ownership, syntax errors and so on) and we have no way of verifying that those things are correct. It is even possible that the app could crash (in some cases).
Is it possible if we can add a plugin uploader from within the application itself? This way we can ensure the correctness of the file and inform the user. We also remove the dependency on the filesystem manual edit and with move with gitaly, this is becoming more important.
@marin /var/opt/gitlab/gitlab-rails/plugins works, I've changed the description. I'm not against adding the ability to upload, in that case we can put the files in /var/opt/gitlab/gitlab-rails/plugins right?
@marin/var/opt/gitlab/gitlab-rails/plugins is same as having plugins in root of GitLab CE repo, right? I want to experiment with this feature today and it seems like having it inside Rails directory is the best way to start.
Why not have all plugins (the ones we curate / test / maintain) and the potential customer plugins in the same directory / using the same mechanism? That would make things easier for both of us, as we only have to maintain a single method of working with these, and the contribution / creation of new plugins could easily be done on basis of our examples.
In general, we should prefer and recommend companies to use our regular APIs though. That's a much easier to maintain approach (for them) and doesn't force us to be more careful with these integration points.
is same as having plugins in root of GitLab CE repo
@dzaporozhets It is not the same as Rails root, but we have a way of creating that directory during the build. Ideally, the path should be configurable but we can discuss that once we have an idea of how this could look.
I'm very nervous about this. If I understand the architecture correctly, these plugins will execute within GitLab? This could mean that performance could be out of our hands, similar to FireFox, Chrome and - yes - Jenkins. Don't you achieve the same capability by adding a webhook to your own 3rd party app, and then calling back into GitLab via the API if needed. We could provide 'stub apps' in a few languages (Ruby, Node) that accept webhooks and act on them. People can them host them or, better still, easily spin them up in k8s etc...
If you have an app that utilises the API and hooks, then you can achieve richer functionality, although nothing that adds UI unless we provide APIs to do that somehow.
Slack & GitHub are both good examples of this. You wrap API & webhooks into an "App" and then you "install" the app into GitLab either at a server-level, group level or project level. They leverage the community by having a Marketplace or App Directory. This seems to be the defacto model. The model we are proposing seems at odds with this trend, and is also limited to rails, rather than being API-driven.
These will execute as GitLab and can cause performance degradations. But this is the only way to change things like the UI I think. We already have webhooks and custom git hooks https://docs.gitlab.com/ee/administration/custom_hooks.html
Exactly, is there an example of a UI API? Sounds complex.
That is a great example of an alternative approach. Maybe we should work with Fable to find out if this addresses their need.
Additional comment from DZ: We can validate the plugin on load, we send fake data and see if it returns the right result. Same rules as the project service already has in tests. If it doesn't we don't load it and write to a log file.
How will we prevent plugins (in general) from opening security holes?
@brodock realistically we can't do much as we allow execution of the code we did not review. Same when people modify GitLab source code to achieve different functionality. We can improve the situation a bit with few steps:
recommend creators to contribute plugins back so we can maintain it as part of our codebase (review, test etc)
recommend using only self-made plugins. Don't download plugins from the internet
@dzaporozhets introducing plugins also means we need to keep a "stable API" for the pieces of code we allow/encourage extensibility.
But if we have very limited, well-defined plugin interfaces, we may be able to use some Rubocop Cops to mark a plugin as compliant or non-compliant (safe/unsafe).
I've seen many different ways of doing plugins in the past, all of them have pros and cons.
One implementation that I like and I think it's very well done is the plugin system for the OpenProject
@dzaporozhets am I correct to think this would require the plugin to be enabled for each project in the GitLab instance?
A customer for which this is an important feature, wants plugins to be able to respond to system hooks like projects being created to check they already exist in an external system, and create a corresponding project in the external system if not. Additionally it would be preferable if instance pre-recieve hooks could also be managed from within the plugin. This would allow the customer to manage their various hooks in a single location, removing the need to have multiple individual scripts and a separate application listening for system hooks.
Further to @jramsay 's comment, the ability to enable the plugin at the group level would be ideal, with the option of project-specific configuration such as authentication parameters.
am I correct to think this would require the plugin to be enabled for each project in the GitLab instance?
@jramsay yes it will behave exactly like project service (project settings -> integrations page). But I still think about it.
There is an alternative approach I currently consider which is having plugins stateless and execute for every project (or event like system hook) without a possibility to configure anything in the UI.
The new POC executes plugins same as system hooks. So everything you can do with system hook you can do with a plugin. The implementation advantage is it does not affect GitLab database so plugins can be added and removed with fewer efforts.
@dzaporozhets I think it's reasonable if this is CE, it will stimulate the use of it and it's something that will be used by opinionated teams, independent of their size.
Dmytro Zaporozhets (DZ)marked the checklist item Allow local plugins by loading them automatically if they are in a directory that is not under version control in /var/opt/gitlab/gitlab-rails/plugins as completed
marked the checklist item Allow local plugins by loading them automatically if they are in a directory that is not under version control in /var/opt/gitlab/gitlab-rails/plugins as completed
TODO: Decide if we want any UI representation of the feature. For example, render read-only list of plugins at Admin -> System Hooks and Project -> Integrations pages.
I'm concerned how this will affect backwards compatibility and performance. Look at the Wordpress plugin ecosystem. Jenkins security updates hell. It will make it near-impossible to address Ruby release updates - just imagine one plugin adding (native) dependencies. This is obviously a situation where the user is to blame for its own decision making but can reflect poorly on the provider.