Jens Krämer

Redmine Plugin Pitfalls and How to Avoid Them

 |  security, redmine

Redmine is awesome, and there are hundreds of plugins out there that make it even more awesome.

One of the things I do regularly for my clients is to review Redmine plugins in terms of functionality and security. At Planio we have very high standards regarding security and code quality to ensure the stability of our SaaS platform, and there are some very good reasons to apply the same level of care when selecting Redmine plugins for your standalone instance of Redmine.

In this article, I’m going to give you a few guidelines to apply when evaluating Redmine plugins for use in your organization. But first of all - what’s the big deal? It’s just a tiny plugin, the author will surely know what he’s doing, what could possibly go wrong? A lot.

What’s the Risk?

Redmine is a collaboration tool, and as such, it is often set up for access from any place in the world via public internet.

Each new Redmine plugin you introduce increases the attack surface, and one carelessly written plugin can be enough to compromise your Redmine installation and all the data it holds, and may even lead to the whole server being compromised.

What would happen when data stored in your Redmine is lost or even stolen? Things can easily get worse when business partners take note - you cannot even securely run your own project management tool, how can they trust you with their own systems?

Your Redmine is a mission critical system.

What steps would you implement before hiring somebody to work on one of your mission critical software systems?

You probably would want to talk to them, and also have a look at some of the things they did before. By all means you would want to make sure this isn’t the first time they’re touching this kind of software. In short, you’re looking for somebody you can trust.

If your Redmine and the data it holds are relevant to your business, it is essential that you establish this level of trust before letting any piece of third party code anywhere near your production data.

How to Evaluate a Redmine Plugin

Establishing trust with a software author from another continent who probably doesn’t even speak your language might be difficult, even more so if you take into account that he or she also probably has different things to do than being interviewed by you.

But there’s good news - since Redmine and it’s plugins are Open Source you can actually look at the code and establish trust in that. In fact this is one of the big ‘selling’ points of Open Source software - you can, if you want, read and check every single line of code.

But before you do that, here’s a few other (easier) things to consider:

First Look at a Redmine Plugin

There are a number of things you can (and should) do before even looking at the source code. A good source of information is (obviously) the plugin’s home page, be it on Github, at the Redmine Plugin Directory or somewhere else. The ratings and comments in the plugin directory can give you an idea of how popular / widely used a certain plugin is. Also you can see what other plugins the author has registered there.

Supported Redmine versions
Check which versions of Redmine the plugin claims to support. Actively maintained plugins should always support the latest stable release of Redmine (which, by the way, is also the version you should be running).
Plugin history
How long does it exist already? Has it been actively maintained in the past? Plugins hosted on Github or similar have a big plus here, because you can look at the actual commit history. Do not trust plugins that only exist as ZIP file downloads - experienced software developers put their stuff into Git or another SCM system, and they are not afraid to give the public read access to that.
Issue tracker
Both currently open and closed issues are interesting. If and how a plugin’s author responds to issues reported by users in the past gives you an idea about the level of support you can expect in the future. Check currently unresolved issues whether they affect your usage scenario / Redmine version. If there is no public issue tracker, that’s a bad sign. In this case, check the plugin’s page in the Redmine Plugin Directory and the Redmine Plugins Discussion Board, maybe there’s a thread regarding the plugin. Still nothing? Be extra careful. No public information about open and resolved issues can mean anything from ‘nobody uses this plugin’ to ‘we sweep any issues under the rug because they might hurt sales’.
Test cases
Does the plugin have a test suite, and if yes, is it run automatically in a CI system like TravisCI? Does the test suite pass with your version of Redmine? You’ll check the test suite later yourself, but a working continuous integration setup is a big plus.
Plugin author
What do you know about him / her? Do you know (or actually use) other plugins by the same author?

Plugin License

Every Redmine plugin (and any other piece of software as well) should include a LICENSE file at the top level, or at least mention the license in it’s README. If in doubt, contact the author.

Software licensing is a complex topic, especially when non-trivial licenses like the GPL are involved, but I’ll give you a simple rule of thumb:

If the author doesn’t clearly state that you may use and redistribute the complete plugin freely under the terms of the GPL or a GPL-compatible license, don’t use it.

The situation with Redmine and it’s plugins can be compared to Wordpress and Wordpress plugins / themes, which are also covered by the GPL. If you’re interested in the gritty details, or think about using plugins with a different / unclear license, read on. Otherwise, it’s safe to skip to the next step.

Redmine is Free Software licensed under the GPL. Therefore, all Ruby code contained in a Redmine plugin is by definition covered by the GPL as well and has to be released under the GPLv2 or a compatible License. There’s a section in the GPL FAQ dedicated to this exact case. It does not matter what the plugin author thinks about this - it’s simply a consequence of Redmine being licensed under the GPL.

Mixed licenses

Artwork, Javascript (if not derived from Redmine’s Javascript) and anything else in a Redmine plugin that is not Ruby code can be licensed differently if the plugin author chooses to do so.

Using this ‘loophole’, Redmine plugins can be created which, while the contained Ruby code is still GPL, may not be redistributed under the GPL as a whole, because they contain, for example, Javascript code under a different license. There are a bunch of commercial Redmine plugins which fall into this category.

I don’t consider this good practice because it defeats the purpose of the GPL by restricting users’ rights for no good reason. Don’t get me wrong - I thing it’s both ok and possible to make money from of Free Software, but if, as a developer, you have to pull licensing tricks like this you’re doing it wrong.

Therefore as a user, stay away and stick to pure GPL plugins whenever possible.

GPL violations

Unfortunately there’s also some black sheep in the Redmine plugin market who choose to outright violate the GPL by shipping their commercial Redmine plugins with obfuscated Ruby code. I’m not going to name or link to them here - if in doubt, grep the plugin’s source code for RubyEncoder.

It’s up to you if you want to shell out money for such a product of more than questionable ethics, but from a purely technical point of view it would be totally unresponsible to put such a plugin into a production system. The code obfuscation makes it impossible to look at what the code does - does it phone home? Does it open a backdoor to Siberia? You never know, and since you cannot read the code you will never find out.

Stay away under all circumstances.

Why should you care about all this complicated licensing stuff at all? Because as a user of Redmine you already highly profit from Free Software, and voting with your money by not giving it to GPL-violators and -circumventers is a powerful way to actively support Free Software.

Use the Source

With all these things out of the way, and given you still have not ruled out the plugin, it’s time to look at the actual code.

Depending on the size of the plugin this can be a tedious and time consuming task, so I’ll start with some motivating words:

It’s quite easy to create a Redmine plugin using the docs or existing plugins as a guideline. This is a good thing in the first place, but you have to keep this fact in mind: Creating a Redmine plugin doesn’t require very deep knowledge of neither Redmine, nor the underlying technologies, mostly Ruby and Rails. By no means I want to discourage anybody from writing Redmine plugins, or blindly label any plugins from novices as ‘bad quality’. I simply want you to pay attention to what you put into your production system.

Here’s some rather uncomfortable truths about Redmine plugins:

  • there are plugins which were obviously written by people who never touched a Rails project before
  • there are plugins coded in a way that literally violates every convention that was established in years of Ruby, Rails and Redmine development
  • there are plugins that completely lack tests
  • there are plugins that introduce bugs and security flaws of various kinds and severity into the Redmine instance they are running in
  • there are plugins that have been forked so many times it’s next to impossible to tell which of the many different versions you should be using

Sounds scary, but no harm will be caused if you detect these things upfront.

Ready to go? Good. Get the plugin’s source code and actually read it, scanning for code smells, common anti patterns, bugs and security problems. Assuming the plugin follows the general directory layout any Redmine plugin should have (if this is not the case and you find things laid out differently - be careful and try to find out why this is the case), here’s a few common things to do:

First of all, check the plugin’s Gemfile for any dependencies it might declare.

Next is init.rb - this is the central file of any Redmine plugin, loaded by Redmine at startup. Here the plugin registers itself with Redmine and does any necessary setup work like pathing Redmine core classes. Pay special attention - patched core classes are (while certainly necessary in many cases) a major cause of problems during Redmine upgrades or conflicts with other plugins. Follow through any other steps taken in init.rb and check what’s going on - sometimes the patching is done somewhere in lib/ in files loaded here. Also examine any hook methods and view templates tied to view hooks (it’s common but not necessary to have a file named hooks.rb which gets loaded by init.rb). The goal is to get a complete overview of what happens when init.rb is loaded during Redmine startup.

Continue with everything else in lib/. Ideally the plugin does not pollute the top level namespace but keeps it’s stuff in a module named after the plugin, and in a matching directory structure below lib/. Missing namespacing is an easy to spot code smell - a global IssuePatch module in a Redmine plugin is literally asking for trouble. Explicit require statements easily mess up the code reloading in Rails’ development mode, resulting in all kinds of errors when editing code without restarting the server. Therefore well-coded plugins rely on Rails’ auto loading instead of manually requiring source files. While not critical for production environments, a broken development mode is another hint at an inexperienced (or simply sloppy) developer.

After going over every file in lib/, continue with config/routes.rb and everything under app/. The routes give you an idea of how users will interact with the plugin. Check them for unnecessary wild card routing, and from here go through all controllers, their views and helpers. Watch out for cases of potential HTML/JS code injection through uncautious use of raw, html_safe and the like (most often these things are found in helpers and views, but of course may also reside in code called from there). Also check if and how authentication and authorization are handled. You don’t want a plugin to introduce ways to circumvent your carefully thought out role and permission setup.

Do not forget to look into database migrations in db/migrate, if any, and also have a look at any Javascript code in assets/javascripts.

This kind of code review is the hardest part and requires a deep understanding of the Redmine code base. Give this task to the most experienced person you can get hold of.

Finally, Run It

If you didn’t encounter any road blocks until now, it’s time to install the plugin into a Redmine instance for testing. Use the same Redmine version and have the same plugins you’re using in production, but do not do this on your production system!

Make sure Redmine’s test suite (and the tests of any other plugins you might already have) passes before and after installation of the plugin. Try out the plugin, and also run it’s test suite. Check for side effects of the new plugin in other areas - Redmine core functions and any other plugins you have should still work as usual.

The plugin appears to do what it should without breaking anything else? Then finally backup your production system (database and the files folder where your attachments are stored) and install your new plugin. Depending on how busy your site usually is / how complex the setup of the plugin is you might want to schedule a downtime for this and / or do this on a weekend. Just plan for the worst case of having to roll back and restore your Redmine from backups.

Comments

postdante

Thank you for this fine article. Very good summary on best practices in the subject.