diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 000000000..1f1a91bb4
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,10 @@
+<!--
+
+NOTE: the 4.4 branch is currently on security-support only. Nothing will be accepted on this branch that isn't either repository maintenance or fixing a security bug, and the latter shouldn't be a public pull request.
+
+-->
+
+#### Additional info
+<!-- Paste the bug number after the # and after the = in the following line. -->
+* [bug#](https://bugzilla.mozilla.org/show_bug.cgi?id=)
+
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 000000000..30ca4583b
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,82 @@
+# This is a basic workflow to help you get started with Actions
+
+name: Release Tests
+
+# Controls when the action will run. Triggers the workflow on push or pull request
+# events but only for the main branch
+on:
+  push:
+    branches: [ 4.4 ]
+  pull_request:
+    branches: [ 4.4 ]
+  # Allows you to run this workflow manually from the Actions tab
+  workflow_dispatch:
+
+# A workflow run is made up of one or more jobs that can run sequentially or in parallel
+jobs:
+  ubuntu:
+    name: Release Tests on Ubuntu 20.04
+    runs-on: ubuntu-20.04
+    steps:
+      - name: Checkout the repository
+        uses: actions/checkout@v4
+      - name: apt install
+        run: |
+          sudo apt-get update
+          sudo apt-get -y dist-upgrade
+          sudo apt-get install --ignore-hold --allow-downgrades -y \
+          apache2 \
+          mariadb-client-10.3 \
+          netcat \
+          libappconfig-perl \
+          libdate-calc-perl \
+          libtemplate-perl \
+          build-essential \
+          libdatetime-timezone-perl \
+          libdatetime-perl \
+          libemail-address-perl \
+          libemail-sender-perl \
+          libemail-mime-perl \
+          libemail-mime-modifier-perl \
+          libdbi-perl \
+          libdbix-connector-perl \
+          libdbd-mysql-perl \
+          libcgi-pm-perl \
+          libmath-random-isaac-perl \
+          libmath-random-isaac-xs-perl \
+          libapache2-mod-perl2 \
+          libapache2-mod-perl2-dev \
+          libchart-perl \
+          libxml-perl \
+          libxml-twig-perl \
+          perlmagick \
+          libgd-graph-perl \
+          libtemplate-plugin-gd-perl \
+          libsoap-lite-perl \
+          libhtml-scrubber-perl \
+          libjson-rpc-perl \
+          libdaemon-generic-perl \
+          libtheschwartz-perl \
+          libtest-taint-perl \
+          libauthen-radius-perl \
+          libfile-slurp-perl \
+          libencode-detect-perl \
+          libmodule-build-perl \
+          libnet-ldap-perl \
+          libauthen-sasl-perl \
+          libfile-mimeinfo-perl \
+          libhtml-formattext-withlinks-perl \
+          libpod-coverage-perl \
+          liblocal-lib-perl \
+          cpanminus \
+          graphviz
+      # apparently we can't get this from apt on Ubuntu
+      - name: Install Email::Send from CPAN
+        run: 'cpanm --sudo install Return::Value Email::Send'
+      - name: Get Perl Version and debug info
+        run: '/usr/bin/perl -V'
+      - name: Run tests
+        run: |
+          export PATH="${GITHUB_WORKSPACE}/perl5/bin${PATH:+:${PATH}}"
+          export PERL5LIB="${GITHUB_WORKSPACE}/perl5${PERL5LIB:+:${PERL5LIB}}"
+          /usr/bin/perl runtests.pl
diff --git a/Bugzilla/BugMail.pm b/Bugzilla/BugMail.pm
index 5a2c9b788..644ed1f1c 100644
--- a/Bugzilla/BugMail.pm
+++ b/Bugzilla/BugMail.pm
@@ -387,9 +387,10 @@ sub _generate_bugmail {
 
     # TT trims the trailing newline, and threadingmarker may be ignored.
     my $email = new Email::MIME("$msg_header\n");
-    if (scalar(@parts) == 1) {
-        $email->content_type_set($parts[0]->content_type);
-    } else {
+
+    # If there's only one part, we don't need to set the overall content type
+    # because Email::MIME will automatically take it from that part (bug 1657496)
+    if (scalar(@parts) > 1) {
         $email->content_type_set('multipart/alternative');
         # Some mail clients need same encoding for each part, even empty ones.
         $email->charset_set('UTF-8') if Bugzilla->params->{'utf8'};
diff --git a/Bugzilla/CGI.pm b/Bugzilla/CGI.pm
index 7df916b0c..19332b17a 100644
--- a/Bugzilla/CGI.pm
+++ b/Bugzilla/CGI.pm
@@ -283,6 +283,69 @@ sub close_standby_message {
     }
 }
 
+our $ALLOW_UNSAFE_RESPONSE = 0;
+# responding to text/plain or text/html is safe
+# responding to any request with a referer header is safe
+# some things need to have unsafe responses (attachment.cgi)
+# everything else should get a 403.
+sub _prevent_unsafe_response {
+    my ($self, $headers) = @_;
+    my $safe_content_type_re = qr{
+        ^ (*COMMIT) # COMMIT makes the regex faster
+                    # by preventing back-tracking. see also perldoc pelre.
+        # application/x-javascript, xml, atom+xml, rdf+xml, xml-dtd, and json
+        (?: application/ (?: x(?: -javascript | ml (?: -dtd )? )
+                           | (?: atom | rdf) \+ xml
+                           | json )
+        # text/csv, text/calendar, text/plain, and text/html
+          | text/ (?: c (?: alendar | sv )
+                    | plain
+                    | html )
+        # used for HTTP push responses
+          | multipart/x-mixed-replace)
+    }sx;
+    my $safe_referer_re = do {
+        # Note that urlbase must end with a /.
+        # It almost certainly does, but let's be extra careful.
+        my $urlbase = correct_urlbase();
+        $urlbase =~ s{/$}{};
+        qr{
+            # Begins with literal urlbase
+            ^ (*COMMIT)
+            \Q$urlbase\E
+            # followed by a slash or end of string
+            (?: /
+              | $ )
+        }sx
+    };
+
+    return if $ALLOW_UNSAFE_RESPONSE;
+
+    if (Bugzilla->usage_mode == USAGE_MODE_BROWSER) {
+        # Safe content types are ones that arn't images.
+        # For now let's assume plain text and html are not valid images.
+        my $content_type         = $headers->{'-type'} // $headers->{'-content_type'} // 'text/html';
+        my $is_safe_content_type = $content_type =~ $safe_content_type_re;
+
+        # Safe referers are ones that begin with the urlbase.
+        my $referer         = $self->referer;
+        my $is_safe_referer = $referer && $referer =~ $safe_referer_re;
+
+        if (!$is_safe_referer && !$is_safe_content_type) {
+            print $self->SUPER::header(-type => 'text/html',  -status => '403 Forbidden');
+            if ($content_type ne 'text/html') {
+                print "Untrusted Referer Header\n";
+                if ($ENV{MOD_PERL}) {
+                    my $r = $self->r;
+                    $r->rflush;
+                    $r->status(200);
+                }
+            }
+            exit;
+        }
+    }
+}
+
 # Override header so we can add the cookies in
 sub header {
     my $self = shift;
@@ -293,6 +356,7 @@ sub header {
         # Since we're adding parameters below, we have to name it.
         unshift(@_, '-type' => shift(@_));
     }
+    $self->_prevent_unsafe_response({@_});
 
     if (!$user->id && $user->authorizer->can_login
         && !$self->cookie('Bugzilla_login_request_cookie'))
diff --git a/Bugzilla/Chart.pm b/Bugzilla/Chart.pm
index e343a0535..968d9a09b 100644
--- a/Bugzilla/Chart.pm
+++ b/Bugzilla/Chart.pm
@@ -418,11 +418,9 @@ sub dump {
 
     # Make sure we've read in our data
     my $data = $self->data;
-    
+
     require Data::Dumper;
-    say "<pre>Bugzilla::Chart object:";
-    print html_quote(Data::Dumper::Dumper($self));
-    print "</pre>";
+    return Data::Dumper::Dumper($self);
 }
 
 1;
diff --git a/Bugzilla/Constants.pm b/Bugzilla/Constants.pm
index f35e41625..ae9e8da55 100644
--- a/Bugzilla/Constants.pm
+++ b/Bugzilla/Constants.pm
@@ -182,7 +182,7 @@ use Memoize;
 # CONSTANTS
 #
 # Bugzilla version
-use constant BUGZILLA_VERSION => "4.4.11";
+use constant BUGZILLA_VERSION => "4.4.14";
 
 # Location of the remote and local XML files to track new releases.
 use constant REMOTE_FILE => 'http://updates.bugzilla.org/bugzilla-update.xml';
diff --git a/Bugzilla/DB/Sqlite.pm b/Bugzilla/DB/Sqlite.pm
index 47cb0cd25..3470ffc12 100644
--- a/Bugzilla/DB/Sqlite.pm
+++ b/Bugzilla/DB/Sqlite.pm
@@ -215,6 +215,7 @@ sub sql_date_format {
     my ($self, $date, $format) = @_;
     $format = "%Y.%m.%d %H:%M:%S" if !$format;
     $format =~ s/\%i/\%M/g;
+    $format =~ s/\%s/\%S/g;
     return "STRFTIME(" . $self->quote($format) . ", $date)";
 }
 
diff --git a/Bugzilla/Install/Requirements.pm b/Bugzilla/Install/Requirements.pm
index e00751c84..16a06d5eb 100644
--- a/Bugzilla/Install/Requirements.pm
+++ b/Bugzilla/Install/Requirements.pm
@@ -129,10 +129,12 @@ sub REQUIRED_MODULES {
     },
     # 2.22 fixes various problems related to UTF8 strings in hash keys,
     # as well as line endings on Windows.
+    # 2.28-3.007 are broken, see https://bugzilla.mozilla.org/show_bug.cgi?id=1560873
     {
         package => 'Template-Toolkit',
         module  => 'Template',
-        version => '2.22'
+        version => '2.22',
+        blacklist => ['^2.2[89]$', '^3.00[0-7]$']
     },
     # 2.04 implement the "Test" method (to write to data/mailer.testfile).
     {
@@ -141,6 +143,11 @@ sub REQUIRED_MODULES {
         version => ON_WINDOWS ? '2.16' : '2.04',
         blacklist => ['^2\.196$']
     },
+    {
+        package => 'Email-Address',
+        module  => 'Email::Address',
+        version => 0,
+    },
     {
         package => 'Email-MIME',
         module  => 'Email::MIME',
diff --git a/Bugzilla/Mailer.pm b/Bugzilla/Mailer.pm
index 64640150b..1149eb0ad 100644
--- a/Bugzilla/Mailer.pm
+++ b/Bugzilla/Mailer.pm
@@ -19,8 +19,6 @@ use Bugzilla::Util;
 
 use Date::Format qw(time2str);
 
-use Encode qw(encode);
-use Encode::MIME::Header;
 use Email::Address;
 use Email::MIME;
 # Return::Value 1.666002 pollutes the error log with warnings about this
@@ -71,22 +69,12 @@ sub MessageToMTA {
     # MIME-Version must be set otherwise some mailsystems ignore the charset
     $email->header_set('MIME-Version', '1.0') if !$email->header('MIME-Version');
 
-    # Encode the headers correctly in quoted-printable
+    # Encode the headers correctly.
     foreach my $header ($email->header_names) {
         my @values = $email->header($header);
-        # We don't recode headers that happen multiple times.
-        next if scalar(@values) > 1;
-        if (my $value = $values[0]) {
-            if (Bugzilla->params->{'utf8'} && !utf8::is_utf8($value)) {
-                utf8::decode($value);
-            }
-
-            # avoid excessive line wrapping done by Encode.
-            local $Encode::Encoding{'MIME-Q'}->{'bpl'} = 998;
+        map { utf8::decode($_) if defined($_) && !utf8::is_utf8($_) } @values;
 
-            my $encoded = encode('MIME-Q', $value);
-            $email->header_set($header, $encoded);
-        }
+        $email->header_str_set($header, @values);
     }
 
     my $from = $email->header('From');
diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm
index cfcbc6655..b9cbfcce0 100644
--- a/Bugzilla/Template.pm
+++ b/Bugzilla/Template.pm
@@ -713,12 +713,13 @@ sub create {
             },
 
             # In CSV, quotes are doubled, and any value containing a quote or a
-            # comma is enclosed in quotes. If a field starts with an equals
-            # sign, it is proceed by a space.
+            # comma is enclosed in quotes.
+            # If a field starts with either "=", "+", "-" or "@", it is preceded
+            # by a space to prevent stupid formula execution from Excel & co.
             csv => sub
             {
                 my ($var) = @_;
-                $var = ' ' . $var if substr($var, 0, 1) eq '=';
+                $var = ' ' . $var if $var =~ /^[+=@-]/;
                 # backslash is not special to CSV, but it can be used to confuse some browsers...
                 # so we do not allow it to happen. We only do this for logged-in users.
                 $var =~ s/\\/\x{FF3C}/g if Bugzilla->user->id;
diff --git a/Bugzilla/Update.pm b/Bugzilla/Update.pm
index 29133ecce..71c0dd9cd 100644
--- a/Bugzilla/Update.pm
+++ b/Bugzilla/Update.pm
@@ -47,7 +47,8 @@ sub get_notifications {
             'latest_ver' => $branch->{'att'}->{'vid'},
             'status'     => $branch->{'att'}->{'status'},
             'url'        => $branch->{'att'}->{'url'},
-            'date'       => $branch->{'att'}->{'date'}
+            'date'       => $branch->{'att'}->{'date'},
+            'eos_date'   => exists($branch->{'att'}->{'eos-date'}) ? $branch->{'att'}->{'eos-date'} : undef,
         };
         push(@releases, $release);
     }
@@ -66,6 +67,35 @@ sub get_notifications {
         }
     }
     elsif (Bugzilla->params->{'upgrade_notification'} eq 'latest_stable_release') {
+        # We want the latest stable version for the current branch.
+        # If we are running a development snapshot, we won't match anything.
+        my $branch_version = $current_version[0] . '.' . $current_version[1];
+
+        # We do a string comparison instead of a numerical one, because
+        # e.g. 2.2 == 2.20, but 2.2 ne 2.20 (and 2.2 is indeed much older).
+        @release = grep {$_->{'branch_ver'} eq $branch_version} @releases;
+
+        # If the branch has an end-of-support date listed, we should
+        # strongly suggest to upgrade to the latest stable release
+        # available.
+        if (scalar(@release) && $release[0]->{'status'} ne 'closed'
+            && defined($release[0]->{'eos_date'})) {
+            my $eos_date = $release[0]->{'eos_date'};
+            @release = grep {$_->{'status'} eq 'stable'} @releases;
+            return {'data' => $release[0],
+                    'branch_version' => $branch_version,
+                    'eos_date' => $eos_date};
+        };
+
+        # If the branch is now closed, we should strongly suggest
+        # to upgrade to the latest stable release available.
+        if (scalar(@release) && $release[0]->{'status'} eq 'closed') {
+            @release = grep {$_->{'status'} eq 'stable'} @releases;
+            return {'data' => $release[0], 'deprecated' => $branch_version};
+        }
+
+        # If we get here, then we want to recommend the lastest stable
+        # release without any other messages.
         @release = grep {$_->{'status'} eq 'stable'} @releases;
     }
     elsif (Bugzilla->params->{'upgrade_notification'} eq 'stable_branch_release') {
@@ -77,6 +107,18 @@ sub get_notifications {
         # e.g. 2.2 == 2.20, but 2.2 ne 2.20 (and 2.2 is indeed much older).
         @release = grep {$_->{'branch_ver'} eq $branch_version} @releases;
 
+        # If the branch has an end-of-support date listed, we should
+        # strongly suggest to upgrade to the latest stable release
+        # available.
+       if (scalar(@release) && $release[0]->{'status'} ne 'closed'
+            && defined($release[0]->{'eos_date'})) {
+            my $eos_date = $release[0]->{'eos_date'};
+            @release = grep {$_->{'status'} eq 'stable'} @releases;
+            return {'data' => $release[0],
+                    'branch_version' => $branch_version,
+                    'eos_date' => $eos_date}
+        };
+
         # If the branch is now closed, we should strongly suggest
         # to upgrade to the latest stable release available.
         if (scalar(@release) && $release[0]->{'status'} eq 'closed') {
diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm
index 89fa20026..a6a47fc29 100644
--- a/Bugzilla/User.pm
+++ b/Bugzilla/User.pm
@@ -132,7 +132,19 @@ sub new {
             $_[0] = $param;
         }
     }
-    return $class->SUPER::new(@_);
+
+    $user = $class->SUPER::new(@_);
+
+    # MySQL considers some non-ascii characters such as umlauts to equal
+    # ascii characters returning a user when it should not.
+    if ($user && ref $param eq 'HASH' && exists $param->{name}) {
+        my $login = $param->{name};
+        if (lc $login ne lc $user->login) {
+            $user = undef;
+        }
+    }
+
+    return $user;
 }
 
 sub super_user {
diff --git a/attachment.cgi b/attachment.cgi
index e003e1f12..cfcb8f5f9 100755
--- a/attachment.cgi
+++ b/attachment.cgi
@@ -31,6 +31,7 @@ use Bugzilla::Token;
 use Bugzilla::Keyword;
 
 use Encode qw(encode find_encoding);
+use Encode::MIME::Header; # Required to alter Encode::Encoding{'MIME-Q'}.
 
 # For most scripts we don't make $cgi and $template global variables. But
 # when preparing Bugzilla for mod_perl, this script used these
@@ -39,6 +40,7 @@ use Encode qw(encode find_encoding);
 local our $cgi = Bugzilla->cgi;
 local our $template = Bugzilla->template;
 local our $vars = {};
+local $Bugzilla::CGI::ALLOW_UNSAFE_RESPONSE = 1;
 
 ################################################################################
 # Main Body Execution
diff --git a/chart.cgi b/chart.cgi
index 7f21fd098..6e995a4e0 100755
--- a/chart.cgi
+++ b/chart.cgi
@@ -94,6 +94,13 @@ $user->in_group(Bugzilla->params->{"chartgroup"})
 # Only admins may create public queries
 $user->in_group('admin') || $cgi->delete('public');
 
+if ($cgi->param('debug')
+    && Bugzilla->params->{debug_group}
+    && Bugzilla->user->in_group(Bugzilla->params->{debug_group})
+    ) {
+    $vars->{'debug'} = 1;
+}
+
 # All these actions relate to chart construction.
 if ($action =~ /^(assemble|add|remove|sum|subscribe|unsubscribe)$/) {
     # These two need to be done before the creation of the Chart object, so
@@ -304,9 +311,12 @@ sub plot {
     my $format = $template->get_format("reports/chart", "", scalar($cgi->param('ctype')));
 
     # Debugging PNGs is a pain; we need to be able to see the error messages
-    if ($cgi->param('debug')) {
-        print $cgi->header();
-        $vars->{'chart'}->dump();
+    if (exists $vars->{'debug'}) {
+        # Bug 1439260 - if we're using debug mode, always use the HTML template
+        # which has proper filters in it. Debug forces an HTML content type
+        # anyway, and can cause XSS if we're not filtering the output.
+        $format = $template->get_format("reports/chart", "", "html");
+        $vars->{'debug_dump'} = $vars->{'chart'}->dump();
     }
 
     print $cgi->header($format->{'ctype'});
@@ -348,7 +358,9 @@ sub view {
 
     # If we have having problems with bad data, we can set debug=1 to dump
     # the data structure.
-    $chart->dump() if $cgi->param('debug');
+    if (exists $vars->{'debug'}) {
+        $vars->{'debug_dump'} = $chart->dump();
+    }
 
     $template->process("reports/create-chart.html.tmpl", $vars)
       || ThrowTemplateError($template->error());
diff --git a/report.cgi b/report.cgi
index f4f015b92..4b1356163 100755
--- a/report.cgi
+++ b/report.cgi
@@ -311,7 +311,12 @@ my $format = $template->get_format("reports/report", $formatparam,
 # If we get a template or CGI error, it comes out as HTML, which isn't valid
 # PNG data, and the browser just displays a "corrupt PNG" message. So, you can
 # set debug=1 to always get an HTML content-type, and view the error.
-$format->{'ctype'} = "text/html" if $cgi->param('debug');
+if (exists $vars->{'debug'}) {
+    # Bug 1439260 - if we're using debug mode, always use the HTML template
+    # which has proper filters in it. Debug forces an HTML content type
+    # anyway, and can cause XSS if we're not filtering the output.
+    $format = $template->get_format("reports/report", $formatparam, "html");
+}
 
 my @time = localtime(time());
 my $date = sprintf "%04d-%02d-%02d", 1900+$time[5],$time[4]+1,$time[3];
@@ -321,12 +326,10 @@ print $cgi->header(-type => $format->{'ctype'},
 
 # Problems with this CGI are often due to malformed data. Setting debug=1
 # prints out both data structures.
-if ($cgi->param('debug')) {
+if (exists $vars->{'debug'}) {
     require Data::Dumper;
-    say "<pre>data hash:";
-    say html_quote(Data::Dumper::Dumper(%data));
-    say "\ndata array:";
-    say html_quote(Data::Dumper::Dumper(@image_data)) . "\n\n</pre>";
+    $vars->{'debug_hash'} = Data::Dumper::Dumper(%data);
+    $vars->{'debug_array'} = Data::Dumper::Dumper(@image_data);
 }
 
 # All formats point to the same section of the documentation.
diff --git a/showdependencygraph.cgi b/showdependencygraph.cgi
index 00fd2061a..4a451c104 100755
--- a/showdependencygraph.cgi
+++ b/showdependencygraph.cgi
@@ -52,13 +52,19 @@ sub CreateImagemap {
             $default = qq{<area alt="" shape="default" href="$1">\n};
         }
 
-        if ($line =~ /^rectangle \((.*),(.*)\) \((.*),(.*)\) (http[^ ]*) (\d+)(\\n.*)?$/) {
+        if ($line =~ /^rectangle \((\d+),(\d+)\) \((\d+),(\d+)\) (http[^ ]*) (\d+)(?:\\n.*)?$/) {
             my ($leftx, $rightx, $topy, $bottomy, $url, $bugid) = ($1, $3, $2, $4, $5, $6);
 
             # Pick up bugid from the mapdata label field. Getting the title from
             # bugtitle hash instead of mapdata allows us to get the summary even
             # when showsummary is off, and also gives us status and resolution.
+            # This text is safe; it has already been escaped.
             my $bugtitle = $bugtitles{$bugid};
+
+            # The URL is supposed to be safe, because it's built manually.
+            # But in case someone manages to inject code, it's safer to escape it.
+            $url = html_quote($url);
+
             $map .= qq{<area alt="bug $bugid" name="bug$bugid" shape="rect" } .
                     qq{title="$bugtitle" href="$url" } .
                     qq{coords="$leftx,$topy,$rightx,$bottomy">\n};
diff --git a/t/002goodperl.t b/t/002goodperl.t
index 2cbee8ef5..8bbe657b3 100644
--- a/t/002goodperl.t
+++ b/t/002goodperl.t
@@ -12,7 +12,7 @@
 
 use strict;
 
-use lib 't';
+use lib qw(. lib t);
 
 use Support::Files;
 
diff --git a/t/003safesys.t b/t/003safesys.t
index 17593fbe7..46432662f 100644
--- a/t/003safesys.t
+++ b/t/003safesys.t
@@ -12,7 +12,7 @@
 
 use strict;
 
-use lib 't';
+use lib qw(. lib t);
 
 use Support::Files;
 
diff --git a/t/004template.t b/t/004template.t
index 604559dc0..7e4973c35 100644
--- a/t/004template.t
+++ b/t/004template.t
@@ -11,7 +11,7 @@
 
 use strict;
 
-use lib 't';
+use lib qw(. lib t);
 
 use Support::Templates;
 
diff --git a/t/005whitespace.t b/t/005whitespace.t
index 624df69f6..124fbfe77 100644
--- a/t/005whitespace.t
+++ b/t/005whitespace.t
@@ -11,7 +11,7 @@
 
 use strict;
 
-use lib 't';
+use lib qw(. lib t);
 
 use Support::Files;
 use Support::Templates;
diff --git a/t/006spellcheck.t b/t/006spellcheck.t
index 07cd3ea8c..4382e4f9e 100644
--- a/t/006spellcheck.t
+++ b/t/006spellcheck.t
@@ -10,7 +10,7 @@
 #Bugzilla Test 6#
 ####Spelling#####
 
-use lib 't';
+use lib qw(. lib t);
 use Support::Files;
 
 BEGIN { # yes the indenting is off, deal with it
diff --git a/t/007util.t b/t/007util.t
index 495102ffa..f3c25f076 100644
--- a/t/007util.t
+++ b/t/007util.t
@@ -9,7 +9,7 @@
 #Bugzilla Test 7#
 #####Util.pm#####
 
-use lib 't';
+use lib qw(. lib t);
 use Support::Files;
 use Test::More tests => 17;
 use DateTime;
diff --git a/t/009bugwords.t b/t/009bugwords.t
index 66262655c..a31f5d65d 100644
--- a/t/009bugwords.t
+++ b/t/009bugwords.t
@@ -17,7 +17,7 @@
 
 use strict;
 
-use lib 't';
+use lib qw(. t lib);
 
 use Support::Files;
 use Support::Templates;
diff --git a/t/010dependencies.t b/t/010dependencies.t
index d84688a7e..a6402d3df 100644
--- a/t/010dependencies.t
+++ b/t/010dependencies.t
@@ -66,7 +66,7 @@ foreach my $module (keys %mods) {
             $used =~ s#/#::#g;
             $used =~ s#\.pm$##;
             $used =~ s#\$module#[^:]+#;
-            $used =~ s#\${[^}]+}#[^:]+#;
+            $used =~ s#\$\{[^}]+\}#[^:]+#;
             $used =~ s#[" ]##g;
             push(@use, grep(/^\Q$used\E$/, keys %mods));
         }
diff --git a/t/011pod.t b/t/011pod.t
index c638dbcde..c3b20b650 100644
--- a/t/011pod.t
+++ b/t/011pod.t
@@ -12,7 +12,7 @@
 
 use strict;
 
-use lib 't';
+use lib qw(. lib t);
 
 use Support::Files;
 use Pod::Checker;
diff --git a/taskgraph.json b/taskgraph.json
index a46abe7c2..23eafb9ce 100644
--- a/taskgraph.json
+++ b/taskgraph.json
@@ -10,28 +10,35 @@
       "reruns": 3,
       "maxRunTime": 3000,
       "task": {
+        "expires": "2018-02-18T17:33:38.806Z",
         "metadata": {
           "name": "Basic Sanity Tests"
         },
         "provisionerId": "aws-provisioner-v1",
         "workerType": "b2gtest",
         "payload": {
-          "image": "dklawren/docker-bugzilla",
-          "command": ["/runtests.sh"],
+          "image": "bugzilla/bugzilla-ci",
+          "command": ["runtests.sh"],
           "env": {
             "TEST_SUITE": "sanity"
           },
           "artifacts": {
             "public/runtests_log": {
               "type": "file",
-              "path": "/runtests.log",
-              "expires": "2016-02-17T17:33:38.806Z"
+              "path": "/tmp/runtests.log",
+              "expires": "2018-02-17T17:33:38.806Z"
             }
           }
         },
         "extra": {
           "treeherder": {
-            "symbol": "San"
+            "symbol": "San",
+            "machine": {
+                "platform": "linux64"
+            },
+            "build": {
+                "platform": "linux64"
+            }
           }
         }
       }
@@ -40,28 +47,35 @@
       "reruns": 3,
       "maxRunTime": 3000,
       "task": {
+        "expires": "2018-02-18T17:33:38.806Z",
         "metadata": {
           "name": "Documentation Build Test"
         },
         "provisionerId": "aws-provisioner-v1",
         "workerType": "b2gtest",
         "payload": {
-          "image": "dklawren/docker-bugzilla",
-          "command": ["/runtests.sh"],
+          "image": "bugzilla/bugzilla-ci",
+          "command": ["runtests.sh"],
           "env": {
             "TEST_SUITE": "docs"
           },
           "artifacts": {
             "public/runtests_log": {
               "type": "file",
-              "path": "/runtests.log",
-              "expires": "2016-02-17T17:33:38.806Z"
+              "path": "/tmp/runtests.log",
+              "expires": "2018-02-17T17:33:38.806Z"
             }
           }
         },
         "extra": {
           "treeherder": {
-            "symbol": "Doc"
+            "symbol": "Doc",
+            "machine": {
+                "platform": "linux64"
+            },
+            "build": {
+                "platform": "linux64"
+            }
           }
         }
       }
@@ -70,33 +84,40 @@
       "reruns": 3,
       "maxRunTime": 7200,
       "task": {
+        "expires": "2018-02-18T17:33:38.806Z",
         "metadata": {
           "name": "WebService API Tests (MySQL)"
         },
         "provisionerId": "aws-provisioner-v1",
         "workerType": "b2gtest",
         "payload": {
-          "image": "dklawren/docker-bugzilla",
-          "command": ["/runtests.sh"],
+          "image": "bugzilla/bugzilla-ci",
+          "command": ["runtests.sh"],
           "env": {
             "TEST_SUITE": "webservices"
           },
           "artifacts": {
             "public/runtests_log": {
               "type": "file",
-              "path": "/runtests.log",
-              "expires": "2016-02-17T17:33:38.806Z"
+              "path": "/tmp/runtests.log",
+              "expires": "2018-02-17T17:33:38.806Z"
             },
             "public/httpd_error_log": {
               "type": "file",
               "path": "/var/log/httpd/error_log",
-              "expires": "2016-02-17T17:33:38.806Z"
+              "expires": "2018-02-17T17:33:38.806Z"
             }
           }
         },
         "extra": {
           "treeherder": {
-            "symbol": "API"
+            "symbol": "API",
+            "machine": {
+                "platform": "linux64"
+            },
+            "build": {
+                "platform": "linux64"
+            }
           }
         }
       }
@@ -105,38 +126,45 @@
       "reruns": 3,
       "maxRunTime": 7200,
       "task": {
+        "expires": "2018-02-18T17:33:38.806Z",
         "metadata": {
           "name": "Selenium Tests (MySQL)"
         },
         "provisionerId": "aws-provisioner-v1",
         "workerType": "b2gtest",
         "payload": {
-          "image": "dklawren/docker-bugzilla",
-          "command": ["/runtests.sh"],
+          "image": "bugzilla/bugzilla-ci",
+          "command": ["runtests.sh"],
           "env": {
             "TEST_SUITE": "selenium"
           },
           "artifacts": {
             "public/runtests_log": {
               "type": "file",
-              "path": "/runtests.log",
-              "expires": "2016-02-17T17:33:38.806Z"
+              "path": "/tmp/runtests.log",
+              "expires": "2018-02-17T17:33:38.806Z"
             },
             "public/httpd_error_log": {
               "type": "file",
               "path": "/var/log/httpd/error_log",
-              "expires": "2016-02-17T17:33:38.806Z"
+              "expires": "2018-02-17T17:33:38.806Z"
             },
             "public/selenium_log": {
               "type": "file",
-              "path": "/selenium.log",
-              "expires": "2016-02-17T17:33:38.806Z"
+              "path": "/tmp/selenium.log",
+              "expires": "2018-02-17T17:33:38.806Z"
             }
           }
         },
         "extra": {
           "treeherder": {
-            "symbol": "Sel"
+            "symbol": "Sel",
+            "machine": {
+                "platform": "linux64"
+            },
+            "build": {
+                "platform": "linux64"
+            }
           }
         }
       }
@@ -145,33 +173,41 @@
       "reruns": 3,
       "maxRunTime": 7200,
       "task": {
+        "expires": "2018-02-18T17:33:38.806Z",
         "metadata": {
           "name": "WebService API Tests (Pg)"
         },
         "provisionerId": "aws-provisioner-v1",
         "workerType": "b2gtest",
         "payload": {
-          "image": "dklawren/docker-bugzilla:pgsql",
-          "command": ["/runtests.sh"],
+          "image": "bugzilla/bugzilla-ci",
+          "command": ["runtests.sh"],
           "env": {
+            "BUGS_DB_DRIVER": "pg",
             "TEST_SUITE": "webservices"
           },
           "artifacts": {
             "public/runtests_log": {
               "type": "file",
-              "path": "/runtests.log",
-              "expires": "2016-02-17T17:33:38.806Z"
+              "path": "/tmp/runtests.log",
+              "expires": "2018-02-17T17:33:38.806Z"
             },
             "public/httpd_error_log": {
               "type": "file",
               "path": "/var/log/httpd/error_log",
-              "expires": "2016-02-17T17:33:38.806Z"
+              "expires": "2018-02-17T17:33:38.806Z"
             }
           }
         },
         "extra": {
           "treeherder": {
-            "symbol": "API-Pg"
+            "symbol": "API-Pg",
+            "machine": {
+                "platform": "linux64"
+            },
+            "build": {
+                "platform": "linux64"
+            }
           }
         }
       }
@@ -180,38 +216,46 @@
       "reruns": 3,
       "maxRunTime": 7200,
       "task": {
+        "expires": "2018-02-18T17:33:38.806Z",
         "metadata": {
           "name": "Selenium Tests (Pg)"
         },
         "provisionerId": "aws-provisioner-v1",
         "workerType": "b2gtest",
         "payload": {
-          "image": "dklawren/docker-bugzilla:pgsql",
-          "command": ["/runtests.sh"],
+          "image": "bugzilla/bugzilla-ci",
+          "command": ["runtests.sh"],
           "env": {
+            "BUGS_DB_DRIVER": "pg",
             "TEST_SUITE": "selenium"
           },
           "artifacts": {
             "public/runtests_log": {
               "type": "file",
-              "path": "/runtests.log",
-              "expires": "2016-02-17T17:33:38.806Z"
+              "path": "/tmp/runtests.log",
+              "expires": "2018-02-17T17:33:38.806Z"
             },
             "public/httpd_error_log": {
               "type": "file",
               "path": "/var/log/httpd/error_log",
-              "expires": "2016-02-17T17:33:38.806Z"
+              "expires": "2018-02-17T17:33:38.806Z"
             },
             "public/selenium_log": {
               "type": "file",
-              "path": "/selenium.log",
-              "expires": "2016-02-17T17:33:38.806Z"
+              "path": "/tmp/selenium.log",
+              "expires": "2018-02-17T17:33:38.806Z"
             }
           }
         },
         "extra": {
           "treeherder": {
-            "symbol": "Sel-Pg"
+            "symbol": "Sel-Pg",
+            "machine": {
+                "platform": "linux64"
+            },
+            "build": {
+                "platform": "linux64"
+            }
           }
         }
       }
diff --git a/template/en/default/global/tabs.html.tmpl b/template/en/default/global/tabs.html.tmpl
index 454066889..dc9ca4c0a 100644
--- a/template/en/default/global/tabs.html.tmpl
+++ b/template/en/default/global/tabs.html.tmpl
@@ -25,7 +25,7 @@
             [% tab.label FILTER html %]</td>
         [% ELSE %]
           <td id="tab_[% tab.name FILTER html %]" class="clickable_area"
-              onClick="document.location='[% tab.link FILTER html %]'">
+              onClick="document.location='[% tab.link FILTER js FILTER html %]'">
             <a href="[% tab.link FILTER html %]">[% tab.label FILTER html %]</a>
           </td>
         [% END %]
diff --git a/template/en/default/index.html.tmpl b/template/en/default/index.html.tmpl
index b47b912c0..87cfa5921 100644
--- a/template/en/default/index.html.tmpl
+++ b/template/en/default/index.html.tmpl
@@ -58,6 +58,12 @@ YAHOO.util.Event.onDOMReady(onLoadActions);
 [% IF release %]
   <div id="new_release">
     [% IF release.data %]
+      [% IF release.eos_date %]
+        <p>[% terms.Bugzilla %] [%+ release.branch_version FILTER html %] will
+        no longer receive security updates after [% release.eos_date FILTER html %].
+        You are highly encouraged to upgrade in order to keep your
+        system secure.</p>
+      [% END %]
       [% IF release.deprecated %]
         <p>[% terms.Bugzilla %] [%+ release.deprecated FILTER html %] is no longer
         supported. You are highly encouraged to upgrade in order to keep your
diff --git a/template/en/default/pages/release-notes.html.tmpl b/template/en/default/pages/release-notes.html.tmpl
index 7763413bf..bcec5a13e 100644
--- a/template/en/default/pages/release-notes.html.tmpl
+++ b/template/en/default/pages/release-notes.html.tmpl
@@ -45,6 +45,81 @@
 
 <h2 id="v44_point">Updates in this 4.4.x Release</h2>
 
+<h3>4.4.14</h3>
+
+<p>This release fixes two security issues. See the
+  <a href="https://www.bugzilla.org/security/4.4.13/">Security Advisory</a>
+  for details.</p>
+
+<div style="border: 3px solid red; padding: 0.5em;">
+This will be the last release of the [% terms.Bugzilla %] 4.4 branch unless
+further security issues are found before the EOL date passes.
+[%+ terms.Bugzilla %] 4.4 will reach end of life 4 months after the release of
+Version 4.4.14. Please take the opportunity to upgrade to version 5.2 or newer.
+</div>
+
+<p>This release also contains the following [% terms.bug %] fixes:</p>
+
+<ul>
+  <li>The Email::MIME module changed the way it set content types on emails in
+  version 1.949, causing [% terms.Bugzilla %] to throw an error and preventing
+  emails from being correctly delivered to recipients. We now set the content
+  type correctly on emails.
+  (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1657496">[% terms.Bug %] 1657496</a>)</li>
+
+  <li>Template Toolkit versions 2.28 through 3.007 are blacklisted due to a
+  compatibility issue.  Versions 2.22 through 2.27 and 3.008 and later are
+  still supported.
+  (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1560873">[% terms.Bug %] 1560873</a>)</li>
+
+  <li>[% terms.Bugzilla %] has a dependency on the Email::Address Perl module
+  which was unstated in the dependency list because it was also a dependency of
+  Email::Sender which [% terms.Bugzilla %] also uses. Newer versions of
+  Email::Sender stopped depending on Email::Address, so [% terms.Bugzilla %]
+  now needs to depend on it explicitly.
+  (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1851352">[% terms.Bug %] 1851352</a>)</li>
+
+</ul>
+
+<h3>4.4.13</h3>
+
+<p>This release fixes one security issue. See the
+  <a href="https://www.bugzilla.org/security/4.4.12/">Security Advisory</a>
+  for details.</p>
+
+<p>This release also contains the following [% terms.bug %] fix:</p>
+
+<ul>
+  <li>All the time entries in the 'when' column had the correct date but the time 
+    was fixed to 00:00 when using Sqlite.
+    (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1303702">[% terms.Bug %] 1303702</a>)</li>
+</ul>
+
+<h3>4.4.12</h3>
+
+<p>This release fixes one security issue. See the
+  <a href="https://www.bugzilla.org/security/4.4.11/">Security Advisory</a>
+  for details.</p>
+
+<p>This release also contains the following [% terms.bug %] fixes:</p>
+
+<ul>
+  <li>The <kbd>Encode</kbd> module changed the way it encodes strings, causing
+    email addresses in emails sent by [%terms.Bugzilla %] to be encoded,
+    preventing emails from being correctly delivered to recipients.
+    We now encode email headers correctly.
+    (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1246228">[% terms.Bug %] 1246228</a>)</li>
+  <li>When exporting a buglist as a CSV file, fields starting with either
+    "=", "+", "-" or "@" are preceded by a space to not trigger formula
+    execution in Excel.
+    (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1259881">[% terms.Bug %] 1259881</a>)</li>
+  <li>An extension which allows user-controlled data to be used as a link in
+    tabs could trigger XSS if the data is not correctly sanitized.
+    [%+ terms. Bugzilla %] no longer relies on the extension to do the sanity
+    check. A vanilla installation is not affected as no tab is user-controlled.
+    (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1250114">[% terms.Bug %] 1250114</a>)</li>
+</ul>
+
 <h3>4.4.11</h3>
 
 <p>This release fixes two security issues. See the
diff --git a/template/en/default/reports/chart.html.tmpl b/template/en/default/reports/chart.html.tmpl
index ab334639c..1e908d956 100644
--- a/template/en/default/reports/chart.html.tmpl
+++ b/template/en/default/reports/chart.html.tmpl
@@ -20,6 +20,12 @@
   header_addl_info = time
 %]
 
+[% IF debug %]
+  <p>Bugzilla::Chart object:</p>
+  <pre>
+  [% debug_dump FILTER html %]
+  </pre>
+[% END %]
 <div align="center">
 
   [% imageurl = BLOCK %]chart.cgi?
diff --git a/template/en/default/reports/create-chart.html.tmpl b/template/en/default/reports/create-chart.html.tmpl
index 471a9cb55..543d8bd33 100644
--- a/template/en/default/reports/create-chart.html.tmpl
+++ b/template/en/default/reports/create-chart.html.tmpl
@@ -17,6 +17,13 @@
   title = "Create Chart"
 %]
 
+[% IF debug %]
+  <p>Bugzilla::Chart object:</p>
+  <pre>
+  [% debug_dump FILTER html %]
+  </pre>
+[% END %]
+
 [% PROCESS "reports/series-common.html.tmpl" 
   donames = 1 
 %]
diff --git a/template/en/default/reports/report.html.tmpl b/template/en/default/reports/report.html.tmpl
index 2ca5dd90f..4825e0a66 100644
--- a/template/en/default/reports/report.html.tmpl
+++ b/template/en/default/reports/report.html.tmpl
@@ -61,6 +61,11 @@
 %]
 
 [% IF debug %]
+  <p>Data hash:</p>
+  <pre>[% debug_hash FILTER html %]</pre>
+  <p>Data array:</p>
+  <pre>[% debug_array FILTER html %]</pre>
+  <p>Queries:</p>
   [% FOREACH query = queries %]
     <p>[% query.sql FILTER html %]</p>
   [% END %]
