.. meta::
:description:
Critical documentation for upgrading the Roundup Issue
Tracker. Actions that must be taken when upgrading from
one version to another are documented here.
.. index:: Upgrading
======================================
Upgrading to newer versions of Roundup
======================================
Please read each section carefully and edit the files in your tracker home
accordingly. Note that there is information about upgrade procedures in the
`administration guide`_ in the `Software Upgrade`_ section.
If a specific version transition isn't mentioned here (e.g. 0.6.7 to
0.6.8) then you don't need to do anything. If you're upgrading from
0.5.6 to 0.6.8 though, you'll need to apply the "0.5 to 0.6" and
"0.6.x to 0.6.3" steps.
General steps:
1. Make note of your current Roundup version.
2. Take your Roundup installation offline (web, email,
cron scripts, roundup-admin etc.)
3. Backup your Roundup instance
4. Install the new version of Roundup (preferably in a new virtual
environment)
5. Make version specific changes as described below for
each version transition. If you are starting at 1.5.0
and installing to 2.3.0, you need to make the changes for **all**
versions starting at 1.5 and ending at 2.3. E.G.
1.5.0 -> 1.5.1, 1.5.1 -> 1.6.0, ..., 2.1.0 -> 2.2.0,
2.2.0 -> 2.3.0.
6. Run ``roundup-admin -i migrate`` using
the newer version of Roundup for the instance you are
upgrading. This will update the database if it is
required.
7. Bring your Roundup instance back online
8. Test
Repeat for each tracker instance.
.. note::
The v1.5.x releases of Roundup were the last to support
Python v2.5 and v2.6. Starting with the v1.6 releases of Roundup
Python version 2.7 that is newer than 2.7.2 is required to run
Roundup. Starting with Roundup version 2.0.0 we also support Python 3
versions newer than 3.6. Roundup version 2.5 supports Python
3.7 and newer.
Recent release notes have the following labels:
* **required** - Roundup will not work properly if these steps are not done
* **recommended** - Roundup will still work, but these steps can cause
security or stability issues if not done.
* **optional** - new features or changes to existing features you might
want to use
* **info** - important possibly visible changes in how things operate
If you use virtual environments for your installation, you
can run trackers with different versions of Roundup. So you
can have one tracker using version 2.2.0 and another tracker
using version 1.6.1. This allows you to upgrade trackers one
at a time rather than having to upgrade all your trackers at
once. Note that downgrading may require restoring your
database to an earlier version, so make sure you backed up
your database.
.. note::
This file only includes versions released in the last 10
years. If you are upgrading from an older version, start with the
changes in the `historical migration `_
document.
.. admonition:: Python 2 Support
If you are running Roundup under Python 2, you should make plans to
switch to Python 3. Release 2.4.0 (Jul 2024) is the last release to
officially support Python 2. The next non-patch release scheduled
for 2025 will mark 5 years since Roundup supported Python 3.
.. admonition:: XHTML Support Deprecation Notice
If you are running a tracker where the ``html_version`` setting in
``config.ini`` is ``xhtml``, you should plan to change your
templates to use html (HTML5). If you are affected by this, please
send email to the roundup-users mailing list (roundup-users at
lists.sourceforge.net). Version 2.3.0 is the last version to support
XHTML.
.. raw:: html
Contents:
.. contents::
:local:
.. raw:: html
.. index:: Upgrading; 2.5.0 to 2.6.0
Migrating from 2.5.0 to 2.6.0
=============================
Default Logs Include Unique Request Identifier (info)
-----------------------------------------------------
The default logging format has been changed from::
%(asctime)s %(levelname)s %(message)s
to::
%(asctime)s %(trace_id)s %(levelname)s %(message)s
So logs now look like::
2025-08-20 03:25:00,308 f6RPbT2s70vvJ2jFb9BQNF DEBUG get user1 cached
which in the previous format would look like::
2025-08-20 03:25:00,308 DEBUG get user1 cached
The new format includes ``trace_id`` which is a thread and process
unique identifier for a single request. So you can link together all
of the log lines and determine where a slow down or other
problem occurred.
The logging format is now a ``config.ini`` parameter in the
``logging`` section with the name ``format``. You can change it if you
would like the old logging format without having to create a logging
configuration file. See :ref:`rounduplogging` for details.
Make Pagination Links Keep Search Name (optional)
-------------------------------------------------
When displaying a named search, index templates don't preserve
the name when using the pagination (Next/Prev) links. This is
fixed in the 2.6.0 templates for issues/bugs/tasks. To make the
change to your templates, look for the pagination links (look for
prev or previous case insensitive) in your tracker's html
subdirectory and change::
request.indexargs_url(request.classname,
{'@startwith':prev.first, '@pagesize':prev.size})"
to read::
request.indexargs_url(request.classname,
dict({'@dispname': request.dispname}
if request.dispname
else {},
**{'@startwith':prev.first, '@pagesize':prev.size}))"
This code will be embedded in templating markup that is not shown
above. The change above is for your previous/prev link. The
change for the next pagination link is similar with::
{'@startwith':next.first, '@pagesize':next.size}
replacing::
{'@startwith':prev.first, '@pagesize':prev.size}
in the example.
This moves the existing dictionary used to override the URL
arguments to the second argument inside a ``dict()`` call. It
also adds ``**`` before it. This change creates a new override
dictionary that includes an ``@dispname`` parameter if it is set
in the request. If ``@dispname`` is not set, the existing
dictionary contents are used.
Support authorized changes in your tracker (optional)
-----------------------------------------------------
An auditor can require change verification with user's password.
When changing sensitive information (e.g. passwords) it is
useful to ask for a validated authorization. This makes sure
that the user is present by typing their password.
You can add this to your auditors using the example
:ref:`sensitive_changes`.
To use this, you must copy ``_generic.reauth.html`` into your
tracker's html subdirectory. See the classic template directory for a
copy. If you are using jinja2, see the jinja2 template directory.
Then you can raise a Reauth exception and have the proper page
displayed.
Also javascript *MUST* be turned on if this is used with a file
input. If JavaScript is not turned on, attached files are lost during
the reauth step. Information from other types of inputs (password,
date, text etc.) do not need JavaScript to work.
See :ref:`Confirming the User` in the reference manual for details.
Support for dictConfig Logging Configuration (optional)
-------------------------------------------------------
Roundup's basic log configuration via config.ini has always had the
ability to use an ini style logging configuration to set levels per
log channel, control output file rotation etc.
With Roundup 2.6 you can use a JSON like file to configure logging
using `dictConfig
`_. The
JSON file format as been enhanced to support comments that are
stripped before being processed by the logging system.
You can read about the details in the :ref:`admin manual `.
Fix user.item.html template producing invalid Javascript (optional)
-------------------------------------------------------------------
The html template ``page.html`` in the classic, devel, minimal, and
responsive tracker templates define a ``user_src_input`` macro. This
macro produces invalid javascript for the ``onblur`` event when used
by ``user.item.html``. The only effect from this bug is a javascript
error reported in the user's browser when the user does not have edit
permissions on the page. It doesn't have any user visible impact.
If you want to fix this, replace::
tal:attributes="onblur python:edit_ok and 'split_name(this)';
with::
tal:attributes="onblur python:'split_name(this)' if edit_ok else '';
in the ``html/page.html`` file in your tracker.
Allow users without a password to log in (optional)
---------------------------------------------------
You can configure a tracker to allow a login without a password.
However the default html templates require the password field to
be filled in. This prevents a login with an empty password.
If you don't want to allow a login without a password, you can
skip this section.
This change automatically removes the required attribute if the
``config.ini`` ``login_empty_passwords`` setting is enabled
(true). The default is disabled with the value ``no``).
This change is the default for the tracker templates in 2.6 and
newer.
To add this to your tracker, change the ``page.html`` (for TAL
based trackers) or ``layout/navigation.html`` (for jinja2 trackers).
For TAL trackers, replace the ``required`` parameter by finding
the following password input in the tracker's ``html/page.html``
file::
and modifying it to look like::
The equivalent change for jinja2's
``html/layout/navigation.html`` based template starts with::
and changes to::
REST interface changes (info)
-----------------------------
The default type of a message file (the msg class) is now
``text/plain``. This can be change to a different mime type using
`the interfaces.py file`_. See `the rest documentation on getting file
content for details `_.
Roundup supports a wildcard mime type. So ``text/*`` would match any
text resource. The response to this request should have a full mime
type like ``text/plain`` or ``text/csv`` etc. However Roundup used to
return ``text/*`` which makes it difficult for the client to interpret
the data. This release should do a better job of returning a proper
subtype replacing the ``*``.
The mime type of ``application/*`` resolves to ``application/json`` by
default. Using it before resulted in an error.
Malformed mime types assigned to files/messages could cause a crash,
now they are just ignored.
There have been some internal refactorings and improvements in the
REST code that will make it a bit faster.
Make File Contents Immutable for Everybody (optional)
-----------------------------------------------------
The HTML based interface for files and messages doesn't provide a way
to change file content. However it is possible for privileged people
to modify the content via the web. In most cases, this change will not
be recorded in the audit log. It can be detected by looking at the
change time of the file. Then compare it to the change time of files
before and after it. Since files are created in order, the file
``msg50`` should have a change timestamp after ``msg49`` and before
``msg51``.
The 2.6.0 release includes an immutable_file_contents.py
detector. If you copy the detector into your tracker's detector
directory nobody, including users with admin rights, can change
file/msg contents via Roundup. Changes to files would have to be
done by logging into the Roundup server and editing the files
locally.
For non-admin user's the following edit permission for FileClass based
classes will prevent regular users from changing file content via
Roundup. Remove the existing ``Edit`` permission from your FileClass
based classes. Then add your classname to the loop. The permission
strips ``content`` from the list of editable properties and permits
editing of the other properties::
for cl in 'file', 'msg':
properties = list(x for x in
db.getclass(cl).getprops(protected=False).keys()
if x != 'content')
file_edit_perm = db.security.addPermission(
name='Edit', klass=cl,
properties=properties,
description="User is allowed to edit all %s props except content" % cl)
db.security.addPermissionToRole('User', file_edit_perm)
.. index:: Upgrading; 2.4.0 to 2.5.0
Migrating from 2.4.0 to 2.5.0
=============================
.. _CVE-2025-53865:
XSS security issue with devel and responsive templates (recommended)
--------------------------------------------------------------------
There are actually two different issues under this heading.
1. incorrect use of the ``structure`` keyword with
``tal:content``
2. use of ``tal:replace`` on unsafe input
See the `security page for a link to CVE-2025-53865
`_.
In the discussion below, the :term:`html directory` means one or
more directories listed in the ``templates`` key of your
tracker's ``config.ini`` file.
These directions can be used to solve the XSS security issue with
any version of Roundup. Even if you used a classic or minimal
template, you should check your trackers for these issues. The
classic template fixed most of these many years ago, but the
updates were not made to the devel and responsive templates. No
report of similar issues with the jinja template has been seen.
Incorrect use of structure in templates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The devel and responsive templates prior to Roundup 2.5 used this
construct::
tal:content="structure context/MUMBLE/plain"
Where ``MUMBLE`` is a property of your issues (e.g. title).
This construct allows a URL with a carefully crafted query
parameter to execute arbitrary JavaScript.
You should check all your trackers. The classic template has not
used this construct since at least 2009, but your tracker's
templates may use the offending construct anyway.
This fix will apply if your tracker is based on the responsive or
devel template. Check the TEMPLATE-INFO.txt file in your tracker
home. The template name is the first component of the ``Name``
field. For example a Name like::
Name: responsive-bugtracker
Name: devel-bugtracker
shows that tracker is based on the responsive or devel templates.
.. _cve-2025-53865-fixed:
To fix this, remove the ``structure`` declaration when it is used
with a plain representation. So fixing the code by replacing the
example above with::
tal:content="context/MUMBLE/plain"
prevents the attack.
To check for this issue, search for ``structure`` followed by
``/plain`` in all your html templates. If you are on a Linux/Unix
system you can search the html subdirectory of your tracker with
the following::
grep 'structure.*/plain' *.html
which should return any lines with issues.
.. warning::
Backup the files in the ``html`` subdirectory of your tracker
in case an edit goes wrong.
As an example, you could fix this issue using the GNU sed
command::
sed -i.bak -e '/structure.*\/plain/s/structure.//' *.html
to edit the files in place and remove the structure keyword. It
will create a ``.bak`` file with the original contents of the
file. If your templates were changed, this might still miss some
entries. If you are on windows, some text editors support search
and replace using a regular expression.
If the construct is split across lines::
tal:content="structure
context/MUMBLE/plain"
the commands above will miss the construct. So you should also
search the html files using ``grep /plain *.html`` and verify
that all of the ``context/MUMBLE/plain`` include ``tal:content``
as in the `fixed example above <#cve-2025-53865-fixed>`_. Any
lines that have ``context/MUMBLE/plain`` without ``tal:content=``
before it need to be manually verified/fixed.
The distributed devel and responsive templates do not split the
construct across lines, but if you changed the files it may be
split.
tal:replace used with unsafe input
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The problem was caused by the following markup::
in the head of the ``bug.item.html``, ``task.item.html`` and
other files in the devel and responsive templates.
This was fixed many years ago in the classic template's
``index.item.html``. The classic template replaces the above
construct with::
``tal:content`` explicitly escapes the result unless the
``structure`` directive is used. ``tal:replace`` expects the
result to be safe and usable in an HTML context.
TAL drops any tags that it doesn't know about from the output.
```` results in the value of the
content expression without a surrounding html tag. (Effectively
replacing the construct.)
The following diff for ``bug.item.html`` in the devel template
shows the change to make things safe (remove lines starting with
``-`` and add lines staring with ``+``)::
Bug : - Bug : - New Bug report - username
to::
username
The code audit found the ``tal:replace`` construct is used with
``context/id`` and ``context/designator`` paths. The references
to these paths have been changed to use ``tal:x`` in the classic
template's ``msg.item.html`` file and the classic and minimal
template's ``_generic.collision.html`` file.
These paths are critical to navigation in Roundup and are set
from the path part of the URL. Roundup's URL path validation
makes it unlikely that an attacker could exploit them. If you
wish you can change your templates or copy the corresponding
files from the template if you haven't made local changes.
Also you may have used copies of these insecure templates
elsewhere in your tracker (e.g. to create a feature class). To
find other possible issues you can use the command::
grep -r "tal:replace=" *.html
in your tracker's :term:`html directory`. Check each occurrence
and if needed, change it to the safer form. You should consider
any reference to ``context`` to be under the user's (attacker's)
control. Also ``db`` (excluding ``db/config``) and ``request``
references that use user supplied content
(e.g. ``request/user/username`` above) should be changed to
``tal:x`` form
.. comment:
As part of the analysis, the following command was used to find
potentially vulnerable stuff in the templates. Each grep -v was
removed to display items in that category and they were checked::
grep -r 'tal:replace' . | grep -v 'replace="batch' | \
grep -v 'replace="config' | grep -v 'replace="db/config' | \
grep -v 'replace="structure' | grep -v 'replace="python:' | \
grep -v 'replace="request/'
context/id, context/designator:
assume safe if used in an class.item.html page as the page
wouldn't be shown if they weren't valid numbers/designators.
Might not be ok referenced in a _generic fallback page though.
config, db/config, batch, nothing:
should be safe as they are not under user control
request/classname (python:request._classname), request/template:
should be safe as they are needed to navigate to a display page,
so if they are invalid nothing will be displayed.
utils, python:
assume it's written correctly and is safe (could use some new
tests for the shipped utility functions). The intent of these
can be to deliver blocks of
or get the file in a separate download using a regular script
tag::
You can place these at the end of ``page.html`` just before the
close body ``