Developer doc

From FusionForge Wiki
Jump to: navigation, search

Developers should also refer to the FusionForge Contribution Guide document, that is present in the sources (see a version here : https://fusionforge.org/docman/?group_id=6&view=listfile&dirid=5, built from "src/docs/docbook/docbook/contribution_guide/contribution_guide.xml")

Below is a few things to know about how the code works. Far from complete.

Hacking with Git

As developer, you have to upload your ssh key first. More information: https://lists.fusionforge.org/pipermail/fusionforge-general/2018-April/003057.html Then simply clone the git repository.

git clone git+ssh://scm.fusionforge.org/srv/git/fusionforge/fusionforge.git  # developer access
git clone https://fusionforge.org/anonscm/git/fusionforge/fusionforge.git  # anonymous read-only access
cd fusionforge.
git checkout [master|Branch_5_3|...]


See Translations.

Database access

Database queries go through the db_query_params() method (db_query() is being deprecated to help get rid of a whole class of potential SQL injection bugs). This is a wrapper around the PostgreSQL database access methods, which passes the variable parts of a query as separate parameters, removing the need for careful escaping and unescaping. To get the full benefits of that, it is important that the query itself be immutable, and all variable parts need to go into separate parameters. For instance, a query counting the groups with a given word in their name or their description should read:

$res = db_query_params ('SELECT count(*) FROM groups WHERE group_name LIKE $1 OR description LIKE $2',
                        array ($word, $word)) ;

Thus, even if $word comes from a malicious user query, it can't do any harm in the database.

Note that this prevents usage of WHERE foo IN (...) constructs if the number of elements in the set is not constant. Fortunately, we can use an alternative way, with the WHERE foo = ANY($1), with the values built with the db_string_array_to_any_clause() or db_int_array_to_any_clause() methods:

$values = array (1, 2, 5, 8) ;
$res = db_query_params ('SELECT foo FROM bar WHERE col = ANY($1)',
                        array (db_int_array_to_any_clause($values))) ;

URLs and links

As described in FusionForge/Suggestions/URL relocation, URLs to pages in the forges should always be generated by the util_make_url() function. This allows to keep the URL scheme in a single point, so that individual pages don't have to know or care whether the forge runs in its own virtualhost, or on SSL, or in a subset of the URL space within a vhost, and so on.

util_make_link() can be used to generate links rather than just URLs, with extra parameters to add attributes to the <a ...> element in the generated HTML. A use case is to add a class for CSS styling.


The authentication uses an MD5 password stored in the database by default, but a hook allows to override that with a plugin (see ldapextauth for an example).

FIXME: there's now two user_pw and unix_pw. Also MD5 hashes now can be cracked with large pre-computed reverse hash lists, so it needs to go away.


Up to 5.0

The permission model is RBAC, role-based access control. 'Users' are members of any number of 'groups'. Each membership of a user in a group has a 'role', possibly shared by several users in a group. Each role is specific to a group (no cross-group sharing currently), and it has a set of 'role settings' which are permission bits for the members of the role on the tools of the group.

There is a global admin "role" given to all users member of the admin project, there is no premission control on this user that can add/remove all permissions he wants

There is a specific admin role given to the project admin, each project creator is by default project admin, he can manage roles for other users, give or remove admin role, design new roles, add/remove users of the group he is admin.

Starting with 5.1

The RBAC model has been extended to make it more powerful and flexible. The model and the API are documented on RBAC. The main differences are that a user can have several roles inside a project, there are global roles not attached to a project in particular, and a project can reference external roles (global or belonging to another project) and grant them permissions.

Plugins can define new permissions, and these permissions will be managed by the same page editing the permissions for the traditional tools. See the Mediawiki plugin for an example, in particular the places involving the PluginSpecificRoleSetting class.

exit functions API

The current exit API is described in www/include/exit.php main exit function is exit_error :

function exit_error($text="", $toptab=)

$text is the error message to be display, $toptab is where you want user to land with the error message. There are some wrappers above exit_error :

function exit_permission_denied($reason_descr=,$toptab=)

which call the login system if you're not logged or call exit_error

function exit_no_group()

no params needed

function exit_missing_param($url=,$missing_params=array(),$toptab=)

url should be HTTP_REFERER or any URL you like. missing_params is an array that will be append to the standard error message Missing required parameters

function exit_disabled($toptab=)

to be used when specific functionnality is disabled

function exit_form_double_submit($toptab=)

to be used when double click on submit button. Need to be rethink... I presume.

System security

This describes the concepts of FusionForge that shall ensure security of the underlying server. It describes

  • what the different components of FusionForge should do or not do,
  • what exceptions currently exist,
  • and what technical measures are taken to ensure this.


Web server

  • should not write to the filesystem directly, except to /var/lib/fusionforge (attachments)
  • should only read and write the database
  • Technical measures:
    • web server runs as user www-data
    • user www-data has usually no write access anywhere
    • only where required, write access can be granted (explicitly?) by the admin
  • Exceptions: ftp upload, some plugins


  • Should write only in /var/lib/fusionforge (if all repos, user & groups dirs are located there)
  • Technical measures:
    • cronjob runs as user root
    • most jobs restrict permissions to user fusionforge
    • user gforge can only write to /var/lib/fusionforge
  • Exceptions:
    • pluginman:
      • creates links in source_path/www/plugins
      • creates links in /etc/fusionforge/plugins



e.g. /opt/fusionforge, /usr/share/gforge...

  • contains source code of FF
  • server admin should not have to modify anything here (to simplify updates)
  • modified only by FF developers
  • Exceptions:
    • Links in /opt/fusionforge/www/plugins are set up by pluginman
    • Some plugins require modifications


  • contains configuration files of FF
  • modified by server admin
  • FF code should not modify anything here (to simplify updates)
  • Exceptions:
    • pluginman creates links here
    • configman modifies local.inc
    • setup autogenerates files here (e.g. httpd.conf)
  • Technical measures: no write permissions for www-data or gforge


  • contains files required by the current state of FF
  • modifed by cronjobs
  • Exceptions:
    • ftp upload
    • mediawiki upload
    • Other plugins?
  • Technical measures:
    • write permissions for user fusionforge
    • no write permissions for user www-data


Configuration was previously accessed through a mess of global variables. This is being deprecated in favour of a (hopefully) clean API:

  • forge_get_config(name [, section]): get value of variable "name" in section "section" (defaults to "core");
  • forge_define_config_item(name, section, default): define a new configuration item with given name/section and default value;
  • forge_set_config_item_bool(name, section): tag the variable as boolean, which allows human-readable values in the configuration files (such as yes, true, on and 1; anything else is mapped to false)
  • forge_read_config_file(file): read a *.ini file and inject its contents into the configuration.
  • forge_read_config_dir(path): read all configuration files in a directory.

See Configuration for more details on existing configuration variables.

For shell scripts, there's also a forge_get_config command that behaves like its counterpart in the PHP API: it loads the configuration and prints out the value of the requested variable.

Plugins are encouraged to store their configuration into a pluginname.ini config file, within a section called pluginname. See examples in the existing plugins.

Migration from the previous system can be performed with the migrate-to-ini-files.sh script.

Design notes: FusionForge/Suggestions/Unified config

PHP Debugging

It is possible to debug the PHP execution, for instance by executing in the Virtual machine development environment and stepping through instructions from Eclipse or another IDE.

This may require to share the view of the source between the host, where the IDE is run, and the guest which executes PHP over the DB.

See Debugging PHP over xdebug with Eclipse and Vagrant for the description of the needed configuration bits.

Plugin development

See src/docs/README.Plugins.

Release process

See Release process.

External accounts

See also